Merge branch 'master' into merge6
Signed-off-by: Martin Bremmer <martin.bremmer@adlinktech.com>
This commit is contained in:
commit
660d495746
124 changed files with 5049 additions and 1672 deletions
|
@ -747,27 +747,50 @@ dds_create_participant(
|
|||
* @brief Creates a domain with a given configuration
|
||||
*
|
||||
* To explicitly create a domain based on a configuration passed as a string.
|
||||
* Normally, the domain is created implicitly on the first call to
|
||||
* dds_create_particiant based on the configuration specified throught
|
||||
* the environment. This function allows to by-pass this behaviour.
|
||||
*
|
||||
* It will not be created if a domain with the given domain id already exists.
|
||||
* This could have been created implicitly by a dds_create_participant().
|
||||
*
|
||||
* Please be aware that the given domain_id always takes precedence over the
|
||||
* configuration.
|
||||
*
|
||||
* | domain_id | domain id in config | result
|
||||
* +-----------+---------------------+----------
|
||||
* | n | any (or absent) | n, config is used
|
||||
* | n | m == n | n, config is used
|
||||
* | n | m != n | n, config is ignored: default
|
||||
*
|
||||
* Config models:
|
||||
* 1: <CycloneDDS>
|
||||
* <Domain id="X">...</Domain>
|
||||
* <Domain .../>
|
||||
* </CycloneDDS>
|
||||
* where ... is all that can today be set in children of CycloneDDS
|
||||
* with the exception of the id
|
||||
* 2: <CycloneDDS>
|
||||
* <Domain><Id>X</Id></Domain>
|
||||
* ...
|
||||
* </CycloneDDS>
|
||||
* legacy form, domain id must be the first element in the file with
|
||||
* a value (if nothing has been set previously, it a warning is good
|
||||
* enough)
|
||||
*
|
||||
* Using NULL or "" as config will create a domain with default settings.
|
||||
*
|
||||
*
|
||||
* @param[in] domain The domain to be created. DEFAULT_DOMAIN is not allowed.
|
||||
* @param[in] config A configuration string containing file names and/or XML fragments representing the configuration.
|
||||
*
|
||||
* @returns A return code
|
||||
* @returns A valid entity handle or an error code.
|
||||
*
|
||||
* @retval DDS_RETCODE_OK
|
||||
* The domain with the domain identifier has been created from
|
||||
* given configuration string.
|
||||
* @retval DDS_RETCODE_BAD_PARAMETER
|
||||
* Illegal value for domain id or the configfile parameter is NULL.
|
||||
* @retval DDS_PRECONDITION_NOT_MET
|
||||
* @retval DDS_RETCODE_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_EXPORT dds_entity_t
|
||||
dds_create_domain(const dds_domainid_t domain, const char *config);
|
||||
|
||||
/**
|
||||
|
@ -777,15 +800,10 @@ dds_create_domain(const dds_domainid_t domain, const char *config);
|
|||
* For instance, it will return the Participant that was used when
|
||||
* creating a Publisher (when that Publisher was provided here).
|
||||
*
|
||||
* When a reader or a writer are created with a partition, then a
|
||||
* subscriber or publisher respectively are created implicitly. These
|
||||
* implicit subscribers or publishers will be deleted automatically
|
||||
* when the reader or writer is deleted. However, when this function
|
||||
* returns such an implicit entity, it is from there on out considered
|
||||
* 'explicit'. This means that it isn't deleted automatically anymore.
|
||||
* The application should explicitly call dds_delete on those entities
|
||||
* now (or delete the parent participant which will delete all entities
|
||||
* within its hierarchy).
|
||||
* When a reader or a writer are created with a participant, then a
|
||||
* subscriber or publisher are created implicitly.
|
||||
* This function will return the implicit parent and not the used
|
||||
* participant.
|
||||
*
|
||||
* @param[in] entity Entity from which to get its parent.
|
||||
*
|
||||
|
@ -852,15 +870,10 @@ dds_get_participant(dds_entity_t entity);
|
|||
* When supplying NULL as list and 0 as size, you can use this to acquire
|
||||
* the number of children without having to pre-allocate a list.
|
||||
*
|
||||
* When a reader or a writer are created with a partition, then a
|
||||
* subscriber or publisher respectively are created implicitly. These
|
||||
* implicit subscribers or publishers will be deleted automatically
|
||||
* when the reader or writer is deleted. However, when this function
|
||||
* returns such an implicit entity, it is from there on out considered
|
||||
* 'explicit'. This means that it isn't deleted automatically anymore.
|
||||
* The application should explicitly call dds_delete on those entities
|
||||
* now (or delete the parent participant which will delete all entities
|
||||
* within its hierarchy).
|
||||
* When a reader or a writer are created with a participant, then a
|
||||
* subscriber or publisher are created implicitly.
|
||||
* When used on the participant, this function will return the implicit
|
||||
* subscriber and/or publisher and not the related reader/writer.
|
||||
*
|
||||
* @param[in] entity Entity from which to get its children.
|
||||
* @param[out] children Pre-allocated array to contain the found children.
|
||||
|
@ -869,7 +882,7 @@ dds_get_participant(dds_entity_t entity);
|
|||
* @returns Number of children or an error code.
|
||||
*
|
||||
* @retval >=0
|
||||
* Number of childer found children (can be larger than 'size').
|
||||
* Number of found children (can be larger than 'size').
|
||||
* @retval DDS_RETCODE_ERROR
|
||||
* An internal error has occurred.
|
||||
* @retval DDS_RETCODE_BAD_PARAMETER
|
||||
|
@ -1200,6 +1213,7 @@ dds_wait_for_acks(dds_entity_t publisher_or_writer, dds_duration_t timeout);
|
|||
/**
|
||||
* @brief Creates a new instance of a DDS reader.
|
||||
*
|
||||
* When a participant is used to create a reader, an implicit subscriber is created.
|
||||
* This implicit subscriber will be deleted automatically when the created reader
|
||||
* is deleted.
|
||||
*
|
||||
|
@ -1226,6 +1240,7 @@ dds_create_reader(
|
|||
/**
|
||||
* @brief Creates a new instance of a DDS reader with a custom history cache.
|
||||
*
|
||||
* When a participant is used to create a reader, an implicit subscriber is created.
|
||||
* This implicit subscriber will be deleted automatically when the created reader
|
||||
* is deleted.
|
||||
*
|
||||
|
@ -1273,6 +1288,7 @@ dds_reader_wait_for_historical_data(
|
|||
/**
|
||||
* @brief Creates a new instance of a DDS writer.
|
||||
*
|
||||
* When a participant is used to create a writer, an implicit publisher is created.
|
||||
* This implicit publisher will be deleted automatically when the created writer
|
||||
* is deleted.
|
||||
*
|
||||
|
@ -1696,12 +1712,28 @@ DDS_EXPORT void
|
|||
dds_write_flush(dds_entity_t writer);
|
||||
|
||||
/**
|
||||
* @brief Write a CDR serialized value of a data instance
|
||||
* @brief Write a serialized value of a data instance
|
||||
*
|
||||
* This call causes the writer to write the serialized value that is provided
|
||||
* in the serdata argument.
|
||||
*
|
||||
* @param[in] writer The writer entity.
|
||||
* @param[in] serdata CDR serialized value to be written.
|
||||
* @param[in] serdata Serialized value to be written.
|
||||
*
|
||||
* @returns A dds_return_t indicating success or failure.
|
||||
*
|
||||
* @retval DDS_RETCODE_OK
|
||||
* The writer successfully wrote the serialized value.
|
||||
* @retval DDS_RETCODE_ERROR
|
||||
* An internal error has occurred.
|
||||
* @retval DDS_RETCODE_BAD_PARAMETER
|
||||
* One of the given arguments is not valid.
|
||||
* @retval DDS_RETCODE_ILLEGAL_OPERATION
|
||||
* The operation is invoked on an inappropriate object.
|
||||
* @retval DDS_RETCODE_ALREADY_DELETED
|
||||
* The entity has already been deleted.
|
||||
* @retval DDS_RETCODE_TIMEOUT
|
||||
* The writer failed to write the serialized value reliably within the specified max_blocking_time.
|
||||
*/
|
||||
DDS_EXPORT dds_return_t
|
||||
dds_writecdr(dds_entity_t writer, struct ddsi_serdata *serdata);
|
||||
|
@ -2652,6 +2684,44 @@ dds_take_mask_wl(
|
|||
uint32_t maxs,
|
||||
uint32_t mask);
|
||||
|
||||
/**
|
||||
* @brief Access the collection of serialized data values (of same type) and
|
||||
* sample info from the data reader, readcondition or querycondition.
|
||||
*
|
||||
* This call accesses the serialized data from the data reader, readcondition or
|
||||
* querycondition and makes it available to the application. The serialized data
|
||||
* is made available through \ref ddsi_serdata structures. Once read the data is
|
||||
* removed from the reader and cannot be 'read' or 'taken' again.
|
||||
*
|
||||
* Return value provides information about the number of samples read, which will
|
||||
* be <= maxs. Based on the count, the buffer will contain serialized data to be
|
||||
* read only when valid_data bit in sample info structure is set.
|
||||
* The buffer required for data values, could be allocated explicitly or can
|
||||
* use the memory from data reader to prevent copy. In the latter case, buffer and
|
||||
* sample_info should be returned back, once it is no longer using the data.
|
||||
*
|
||||
* @param[in] reader_or_condition Reader, readcondition or querycondition entity.
|
||||
* @param[out] buf An array of pointers to \ref ddsi_serdata structures that contain
|
||||
* the serialized data. The pointers can be NULL.
|
||||
* @param[in] maxs Maximum number of samples to read.
|
||||
* @param[out] si Pointer to an array of \ref dds_sample_info_t returned for each data value.
|
||||
* @param[in] mask Filter the data based on dds_sample_state_t|dds_view_state_t|dds_instance_state_t.
|
||||
*
|
||||
* @returns A dds_return_t with the number of samples read or an error code.
|
||||
*
|
||||
* @retval >=0
|
||||
* Number of samples read.
|
||||
* @retval DDS_RETCODE_ERROR
|
||||
* An internal error has occurred.
|
||||
* @retval DDS_RETCODE_BAD_PARAMETER
|
||||
* One of the given arguments is not valid.
|
||||
* @retval DDS_RETCODE_ILLEGAL_OPERATION
|
||||
* The operation is invoked on an inappropriate object.
|
||||
* @retval DDS_RETCODE_ALREADY_DELETED
|
||||
* The entity has already been deleted.
|
||||
* @retval DDS_RETCODE_PRECONDITION_NOT_MET
|
||||
* The precondition for this operation is not met.
|
||||
*/
|
||||
DDS_EXPORT dds_return_t
|
||||
dds_takecdr(
|
||||
dds_entity_t reader_or_condition,
|
||||
|
@ -3244,6 +3314,29 @@ dds_get_matched_publication_data (
|
|||
dds_entity_t reader,
|
||||
dds_instance_handle_t ih);
|
||||
|
||||
/**
|
||||
* @brief This operation manually asserts the liveliness of a writer
|
||||
* or domain participant.
|
||||
*
|
||||
* This operation manually asserts the liveliness of a writer
|
||||
* or domain participant. This is used in combination with the Liveliness
|
||||
* QoS policy to indicate that the entity remains active. This operation need
|
||||
* only be used if the liveliness kind in the QoS is either
|
||||
* DDS_LIVELINESS_MANUAL_BY_PARTICIPANT or DDS_LIVELINESS_MANUAL_BY_TOPIC.
|
||||
*
|
||||
* @param[in] entity A domain participant or writer
|
||||
*
|
||||
* @returns A dds_return_t indicating success or failure.
|
||||
*
|
||||
* @retval DDS_RETCODE_OK
|
||||
* The operation was successful.
|
||||
* @retval DDS_RETCODE_ILLEGAL_OPERATION
|
||||
* The operation is invoked on an inappropriate object.
|
||||
*/
|
||||
DDS_EXPORT dds_return_t
|
||||
dds_assert_liveliness (
|
||||
dds_entity_t entity);
|
||||
|
||||
#if defined (__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
DDS_EXPORT dds_return_t dds_domain_create_internal (dds_domain **domain_out, dds_domainid_t id, bool use_existing, const char *config) ddsrt_nonnull((1,4));
|
||||
DDS_EXPORT dds_entity_t dds_domain_create_internal (dds_domain **domain_out, dds_domainid_t id, bool implicit, const char *config) ddsrt_nonnull((1,4));
|
||||
DDS_EXPORT dds_domain *dds_domain_find_locked (dds_domainid_t id);
|
||||
|
||||
#if defined (__cplusplus)
|
||||
|
|
|
@ -24,6 +24,7 @@ dds_entity_init(
|
|||
dds_entity * e,
|
||||
dds_entity * parent,
|
||||
dds_entity_kind_t kind,
|
||||
bool implicit,
|
||||
dds_qos_t * qos,
|
||||
const dds_listener_t *listener,
|
||||
status_mask_t mask);
|
||||
|
@ -38,6 +39,12 @@ dds_entity_register_child (
|
|||
DDS_EXPORT void
|
||||
dds_entity_add_ref_locked(dds_entity *e);
|
||||
|
||||
DDS_EXPORT void
|
||||
dds_entity_drop_ref(dds_entity *e);
|
||||
|
||||
DDS_EXPORT void
|
||||
dds_entity_unpin_and_drop_ref (dds_entity *e);
|
||||
|
||||
#define DEFINE_ENTITY_LOCK_UNLOCK(qualifier_, type_, kind_) \
|
||||
qualifier_ dds_return_t type_##_lock (dds_entity_t hdl, type_ **x) \
|
||||
{ \
|
||||
|
@ -96,6 +103,8 @@ dds_entity_pin (
|
|||
dds_entity_t hdl,
|
||||
dds_entity **eptr);
|
||||
|
||||
DDS_EXPORT dds_return_t dds_entity_pin_for_delete (dds_entity_t hdl, bool explicit, dds_entity **eptr);
|
||||
|
||||
DDS_EXPORT void dds_entity_unpin (
|
||||
dds_entity *e);
|
||||
|
||||
|
|
|
@ -72,9 +72,11 @@ typedef int32_t dds_handle_t;
|
|||
|
||||
/* Closing & closed can be combined, but having two gives a means for enforcing
|
||||
that close() be called first, then close_wait(), and then delete(). */
|
||||
#define HDL_FLAG_CLOSING (0x80000000u)
|
||||
#define HDL_FLAG_CLOSED (0x40000000u)
|
||||
#define HDL_FLAG_PENDING (0x20000000u)
|
||||
#define HDL_FLAG_CLOSING (0x80000000u)
|
||||
#define HDL_FLAG_DELETE_DEFERRED (0x40000000u)
|
||||
#define HDL_FLAG_PENDING (0x20000000u)
|
||||
#define HDL_FLAG_IMPLICIT (0x10000000u)
|
||||
#define HDL_FLAG_ALLOW_CHILDREN (0x08000000u) /* refc counts children */
|
||||
|
||||
struct dds_handle_link {
|
||||
dds_handle_t hdl;
|
||||
|
@ -116,7 +118,9 @@ dds_handle_server_fini(void);
|
|||
*/
|
||||
DDS_EXPORT dds_handle_t
|
||||
dds_handle_create(
|
||||
struct dds_handle_link *link);
|
||||
struct dds_handle_link *link,
|
||||
bool implicit,
|
||||
bool allow_children);
|
||||
|
||||
|
||||
/*
|
||||
|
@ -124,7 +128,7 @@ dds_handle_create(
|
|||
*/
|
||||
DDS_EXPORT dds_return_t
|
||||
dds_handle_register_special (
|
||||
struct dds_handle_link *link, dds_handle_t handle);
|
||||
struct dds_handle_link *link, bool implicit, bool allow_children, dds_handle_t handle);
|
||||
|
||||
DDS_EXPORT void dds_handle_unpend (struct dds_handle_link *link);
|
||||
|
||||
|
@ -181,6 +185,8 @@ DDS_EXPORT void
|
|||
dds_handle_unpin(
|
||||
struct dds_handle_link *link);
|
||||
|
||||
int32_t dds_handle_pin_for_delete (dds_handle_t hdl, bool explicit, struct dds_handle_link **link);
|
||||
bool dds_handle_drop_childref_and_pin (struct dds_handle_link *link, bool may_delete_parent);
|
||||
|
||||
/*
|
||||
* Check if the handle is closed.
|
||||
|
@ -195,11 +201,15 @@ dds_handle_unpin(
|
|||
|
||||
DDS_EXPORT void dds_handle_add_ref (struct dds_handle_link *link);
|
||||
DDS_EXPORT bool dds_handle_drop_ref (struct dds_handle_link *link);
|
||||
DDS_EXPORT bool dds_handle_close (struct dds_handle_link *link);
|
||||
DDS_EXPORT bool dds_handle_unpin_and_drop_ref (struct dds_handle_link *link);
|
||||
|
||||
DDS_EXPORT inline bool dds_handle_is_closed (struct dds_handle_link *link) {
|
||||
return (ddsrt_atomic_ld32 (&link->cnt_flags) & (HDL_FLAG_CLOSED | HDL_FLAG_CLOSING)) != 0;
|
||||
return (ddsrt_atomic_ld32 (&link->cnt_flags) & HDL_FLAG_CLOSING) != 0;
|
||||
}
|
||||
|
||||
DDS_EXPORT bool dds_handle_is_not_refd (struct dds_handle_link *link);
|
||||
|
||||
#if defined (__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -21,6 +21,13 @@ extern "C" {
|
|||
|
||||
DEFINE_ENTITY_LOCK_UNLOCK(inline, dds_publisher, DDS_KIND_PUBLISHER)
|
||||
|
||||
dds_entity_t
|
||||
dds__create_publisher_l(
|
||||
struct dds_participant *participant, /* entity-lock must be held */
|
||||
bool implicit,
|
||||
const dds_qos_t *qos,
|
||||
const dds_listener_t *listener);
|
||||
|
||||
dds_return_t dds_publisher_begin_coherent (dds_entity_t e);
|
||||
dds_return_t dds_publisher_end_coherent (dds_entity_t e);
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ DEFINE_ENTITY_LOCK_UNLOCK(inline, dds_subscriber, DDS_KIND_SUBSCRIBER)
|
|||
dds_entity_t
|
||||
dds__create_subscriber_l(
|
||||
struct dds_participant *participant, /* entity-lock must be held */
|
||||
bool implicit,
|
||||
const dds_qos_t *qos,
|
||||
const dds_listener_t *listener);
|
||||
|
||||
|
|
|
@ -245,7 +245,7 @@ typedef struct dds_participant {
|
|||
|
||||
typedef struct dds_reader {
|
||||
struct dds_entity m_entity;
|
||||
const struct dds_topic *m_topic;
|
||||
struct dds_topic *m_topic;
|
||||
struct dds_rhc *m_rhc; /* aliases m_rd->rhc with a wider interface, FIXME: but m_rd owns it for resource management */
|
||||
struct reader *m_rd;
|
||||
bool m_data_on_readers;
|
||||
|
@ -265,7 +265,7 @@ typedef struct dds_reader {
|
|||
|
||||
typedef struct dds_writer {
|
||||
struct dds_entity m_entity;
|
||||
const struct dds_topic *m_topic;
|
||||
struct dds_topic *m_topic;
|
||||
struct nn_xpack *m_xp;
|
||||
struct writer *m_wr;
|
||||
struct whc *m_whc; /* FIXME: ownership still with underlying DDSI writer (cos of DDSI built-in writers )*/
|
||||
|
|
|
@ -131,7 +131,7 @@ bool dds__validate_builtin_reader_qos (const dds_domain *dom, dds_entity_t topic
|
|||
static dds_entity_t dds__create_builtin_subscriber (dds_participant *participant)
|
||||
{
|
||||
dds_qos_t *qos = dds__create_builtin_qos ();
|
||||
dds_entity_t sub = dds__create_subscriber_l (participant, qos, NULL);
|
||||
dds_entity_t sub = dds__create_subscriber_l (participant, false, qos, NULL);
|
||||
dds_delete_qos (qos);
|
||||
return sub;
|
||||
}
|
||||
|
|
|
@ -48,16 +48,14 @@ static int dds_domain_compare (const void *va, const void *vb)
|
|||
static const ddsrt_avl_treedef_t dds_domaintree_def = DDSRT_AVL_TREEDEF_INITIALIZER (
|
||||
offsetof (dds_domain, m_node), offsetof (dds_domain, m_id), dds_domain_compare, 0);
|
||||
|
||||
static dds_return_t dds_domain_init (dds_domain *domain, dds_domainid_t domain_id, const char *config)
|
||||
static dds_entity_t dds_domain_init (dds_domain *domain, dds_domainid_t domain_id, const char *config, bool implicit)
|
||||
{
|
||||
dds_return_t ret = DDS_RETCODE_OK;
|
||||
dds_entity_t domh;
|
||||
uint32_t len;
|
||||
dds_entity_t domain_handle;
|
||||
|
||||
if ((domain_handle = dds_entity_init (&domain->m_entity, &dds_global.m_entity, DDS_KIND_DOMAIN, NULL, NULL, 0)) < 0)
|
||||
return domain_handle;
|
||||
if ((domh = dds_entity_init (&domain->m_entity, &dds_global.m_entity, DDS_KIND_DOMAIN, implicit, NULL, NULL, 0)) < 0)
|
||||
return domh;
|
||||
domain->m_entity.m_domain = domain;
|
||||
domain->m_entity.m_flags |= DDS_ENTITY_IMPLICIT;
|
||||
domain->m_entity.m_iid = ddsi_iid_gen ();
|
||||
|
||||
domain->gv.tstart = now ();
|
||||
|
@ -90,7 +88,7 @@ static dds_return_t dds_domain_init (dds_domain *domain, dds_domainid_t domain_i
|
|||
if (domain->cfgst == NULL)
|
||||
{
|
||||
DDS_ILOG (DDS_LC_CONFIG, domain_id, "Failed to parse configuration\n");
|
||||
ret = DDS_RETCODE_ERROR;
|
||||
domh = DDS_RETCODE_ERROR;
|
||||
goto fail_config;
|
||||
}
|
||||
|
||||
|
@ -100,14 +98,14 @@ static dds_return_t dds_domain_init (dds_domain *domain, dds_domainid_t domain_i
|
|||
if (rtps_config_prep (&domain->gv, domain->cfgst) != 0)
|
||||
{
|
||||
DDS_ILOG (DDS_LC_CONFIG, domain->m_id, "Failed to configure RTPS\n");
|
||||
ret = DDS_RETCODE_ERROR;
|
||||
domh = DDS_RETCODE_ERROR;
|
||||
goto fail_rtps_config;
|
||||
}
|
||||
|
||||
if (rtps_init (&domain->gv) < 0)
|
||||
{
|
||||
DDS_ILOG (DDS_LC_CONFIG, domain->m_id, "Failed to initialize RTPS\n");
|
||||
ret = DDS_RETCODE_ERROR;
|
||||
domh = DDS_RETCODE_ERROR;
|
||||
goto fail_rtps_init;
|
||||
}
|
||||
|
||||
|
@ -122,14 +120,14 @@ static dds_return_t dds_domain_init (dds_domain *domain, dds_domainid_t domain_i
|
|||
if (dds_global.threadmon == NULL)
|
||||
{
|
||||
DDS_ILOG (DDS_LC_CONFIG, domain->m_id, "Failed to create a thread liveliness monitor\n");
|
||||
ret = DDS_RETCODE_OUT_OF_RESOURCES;
|
||||
domh = DDS_RETCODE_OUT_OF_RESOURCES;
|
||||
goto fail_threadmon_new;
|
||||
}
|
||||
/* FIXME: thread properties */
|
||||
if (ddsi_threadmon_start (dds_global.threadmon, "threadmon") < 0)
|
||||
{
|
||||
DDS_ILOG (DDS_LC_ERROR, domain->m_id, "Failed to start the thread liveliness monitor\n");
|
||||
ret = DDS_RETCODE_ERROR;
|
||||
domh = DDS_RETCODE_ERROR;
|
||||
goto fail_threadmon_start;
|
||||
}
|
||||
}
|
||||
|
@ -159,16 +157,17 @@ static dds_return_t dds_domain_init (dds_domain *domain, dds_domainid_t domain_i
|
|||
if (rtps_start (&domain->gv) < 0)
|
||||
{
|
||||
DDS_ILOG (DDS_LC_CONFIG, domain->m_id, "Failed to start RTPS\n");
|
||||
ret = DDS_RETCODE_ERROR;
|
||||
domh = DDS_RETCODE_ERROR;
|
||||
goto fail_rtps_start;
|
||||
}
|
||||
|
||||
if (domain->gv.config.liveliness_monitoring)
|
||||
ddsi_threadmon_register_domain (dds_global.threadmon, &domain->gv);
|
||||
dds_entity_init_complete (&domain->m_entity);
|
||||
return DDS_RETCODE_OK;
|
||||
return domh;
|
||||
|
||||
fail_rtps_start:
|
||||
dds__builtin_fini (domain);
|
||||
if (domain->gv.config.liveliness_monitoring && dds_global.threadmon_count == 1)
|
||||
ddsi_threadmon_stop (dds_global.threadmon);
|
||||
fail_threadmon_start:
|
||||
|
@ -184,7 +183,7 @@ fail_rtps_config:
|
|||
config_fini (domain->cfgst);
|
||||
fail_config:
|
||||
dds_handle_delete (&domain->m_entity.m_hdllink);
|
||||
return ret;
|
||||
return domh;
|
||||
}
|
||||
|
||||
dds_domain *dds_domain_find_locked (dds_domainid_t id)
|
||||
|
@ -192,37 +191,25 @@ dds_domain *dds_domain_find_locked (dds_domainid_t id)
|
|||
return ddsrt_avl_lookup (&dds_domaintree_def, &dds_global.m_domains, &id);
|
||||
}
|
||||
|
||||
dds_return_t dds_domain_create_internal (dds_domain **domain_out, dds_domainid_t id, bool use_existing, const char *config)
|
||||
dds_entity_t dds_domain_create_internal (dds_domain **domain_out, dds_domainid_t id, bool implicit, const char *config)
|
||||
{
|
||||
struct dds_domain *dom;
|
||||
dds_return_t ret;
|
||||
dds_entity_t domh = DDS_RETCODE_ERROR;
|
||||
|
||||
/* FIXME: should perhaps lock parent object just like everywhere */
|
||||
ddsrt_mutex_lock (&dds_global.m_mutex);
|
||||
retry:
|
||||
if (id != DDS_DOMAIN_DEFAULT)
|
||||
{
|
||||
if ((dom = dds_domain_find_locked (id)) == NULL)
|
||||
ret = DDS_RETCODE_NOT_FOUND;
|
||||
else
|
||||
ret = DDS_RETCODE_OK;
|
||||
}
|
||||
dom = dds_domain_find_locked (id);
|
||||
else
|
||||
{
|
||||
if ((dom = ddsrt_avl_find_min (&dds_domaintree_def, &dds_global.m_domains)) != NULL)
|
||||
ret = DDS_RETCODE_OK;
|
||||
else
|
||||
ret = DDS_RETCODE_NOT_FOUND;
|
||||
}
|
||||
dom = ddsrt_avl_find_min (&dds_domaintree_def, &dds_global.m_domains);
|
||||
|
||||
switch (ret)
|
||||
if (dom)
|
||||
{
|
||||
case DDS_RETCODE_OK:
|
||||
if (!use_existing)
|
||||
{
|
||||
ret = DDS_RETCODE_PRECONDITION_NOT_MET;
|
||||
break;
|
||||
}
|
||||
if (!implicit)
|
||||
domh = DDS_RETCODE_PRECONDITION_NOT_MET;
|
||||
else
|
||||
{
|
||||
ddsrt_mutex_lock (&dom->m_entity.m_mutex);
|
||||
if (dds_handle_is_closed (&dom->m_entity.m_hdllink))
|
||||
{
|
||||
|
@ -230,52 +217,54 @@ dds_return_t dds_domain_create_internal (dds_domain **domain_out, dds_domainid_t
|
|||
ddsrt_cond_wait (&dds_global.m_cond, &dds_global.m_mutex);
|
||||
goto retry;
|
||||
}
|
||||
else
|
||||
dds_entity_add_ref_locked (&dom->m_entity);
|
||||
dds_handle_repin (&dom->m_entity.m_hdllink);
|
||||
domh = dom->m_entity.m_hdllink.hdl;
|
||||
ddsrt_mutex_unlock (&dom->m_entity.m_mutex);
|
||||
*domain_out = dom;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dom = dds_alloc (sizeof (*dom));
|
||||
if ((domh = dds_domain_init (dom, id, config, implicit)) < 0)
|
||||
dds_free (dom);
|
||||
else
|
||||
{
|
||||
ddsrt_mutex_lock (&dom->m_entity.m_mutex);
|
||||
ddsrt_avl_insert (&dds_domaintree_def, &dds_global.m_domains, dom);
|
||||
dds_entity_register_child (&dds_global.m_entity, &dom->m_entity);
|
||||
if (implicit)
|
||||
{
|
||||
dds_entity_add_ref_locked (&dom->m_entity);
|
||||
ddsrt_mutex_unlock (&dom->m_entity.m_mutex);
|
||||
*domain_out = dom;
|
||||
dds_handle_repin (&dom->m_entity.m_hdllink);
|
||||
}
|
||||
break;
|
||||
case DDS_RETCODE_NOT_FOUND:
|
||||
dom = dds_alloc (sizeof (*dom));
|
||||
if ((ret = dds_domain_init (dom, id, config)) < 0)
|
||||
dds_free (dom);
|
||||
else
|
||||
{
|
||||
ddsrt_mutex_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;
|
||||
domh = dom->m_entity.m_hdllink.hdl;
|
||||
ddsrt_mutex_unlock (&dom->m_entity.m_mutex);
|
||||
*domain_out = dom;
|
||||
}
|
||||
}
|
||||
ddsrt_mutex_unlock (&dds_global.m_mutex);
|
||||
return ret;
|
||||
return domh;
|
||||
}
|
||||
|
||||
dds_return_t dds_create_domain(const dds_domainid_t domain, const char *config)
|
||||
dds_entity_t dds_create_domain (const dds_domainid_t domain, const char *config)
|
||||
{
|
||||
dds_domain *dom;
|
||||
dds_entity_t ret;
|
||||
|
||||
if (domain == DDS_DOMAIN_DEFAULT || config == NULL)
|
||||
if (domain == DDS_DOMAIN_DEFAULT)
|
||||
return DDS_RETCODE_BAD_PARAMETER;
|
||||
|
||||
if (config == NULL)
|
||||
config = "";
|
||||
|
||||
/* Make sure DDS instance is initialized. */
|
||||
if ((ret = dds_init ()) < 0)
|
||||
goto err_dds_init;
|
||||
return ret;
|
||||
|
||||
if ((ret = dds_domain_create_internal (&dom, domain, false, config)) < 0)
|
||||
goto err_domain_create;
|
||||
|
||||
return DDS_RETCODE_OK;
|
||||
|
||||
err_domain_create:
|
||||
dds_delete_impl_pinned (&dds_global.m_entity, DIS_EXPLICIT);
|
||||
err_dds_init:
|
||||
ret = dds_domain_create_internal (&dom, domain, false, config);
|
||||
dds_entity_unpin_and_drop_ref (&dds_global.m_entity);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -368,5 +357,5 @@ void dds_write_set_batch (bool enable)
|
|||
}
|
||||
}
|
||||
ddsrt_mutex_unlock (&dds_global.m_mutex);
|
||||
dds_delete_impl_pinned (&dds_global.m_entity, DIS_EXPLICIT);
|
||||
dds_entity_unpin_and_drop_ref (&dds_global.m_entity);
|
||||
}
|
||||
|
|
|
@ -22,7 +22,9 @@
|
|||
#include "dds__qos.h"
|
||||
#include "dds__topic.h"
|
||||
#include "dds/version.h"
|
||||
#include "dds/ddsi/ddsi_pmd.h"
|
||||
#include "dds/ddsi/q_xqos.h"
|
||||
#include "dds/ddsi/q_transmit.h"
|
||||
|
||||
extern inline dds_entity *dds_entity_from_handle_link (struct dds_handle_link *hdllink);
|
||||
extern inline bool dds_entity_is_enabled (const dds_entity *e);
|
||||
|
@ -80,11 +82,34 @@ const ddsrt_avl_treedef_t dds_entity_children_td = DDSRT_AVL_TREEDEF_INITIALIZER
|
|||
static void dds_entity_observers_signal (dds_entity *observed, uint32_t status);
|
||||
static void dds_entity_observers_signal_delete (dds_entity *observed);
|
||||
|
||||
static dds_return_t dds_delete_impl (dds_entity_t entity, enum delete_impl_state delstate);
|
||||
static dds_return_t really_delete_pinned_closed_locked (struct dds_entity *e, enum delete_impl_state delstate);
|
||||
|
||||
void dds_entity_add_ref_locked (dds_entity *e)
|
||||
{
|
||||
dds_handle_add_ref (&e->m_hdllink);
|
||||
}
|
||||
|
||||
void dds_entity_drop_ref (dds_entity *e)
|
||||
{
|
||||
if (dds_handle_drop_ref (&e->m_hdllink))
|
||||
{
|
||||
dds_return_t ret = dds_delete_impl(e->m_hdllink.hdl, DIS_EXPLICIT);
|
||||
assert (ret == DDS_RETCODE_OK);
|
||||
(void) ret;
|
||||
}
|
||||
}
|
||||
|
||||
void dds_entity_unpin_and_drop_ref (dds_entity *e)
|
||||
{
|
||||
if (dds_handle_unpin_and_drop_ref (&e->m_hdllink))
|
||||
{
|
||||
dds_return_t ret = dds_delete_impl(e->m_hdllink.hdl, DIS_EXPLICIT);
|
||||
assert (ret == DDS_RETCODE_OK);
|
||||
(void) ret;
|
||||
}
|
||||
}
|
||||
|
||||
static bool entity_has_status (const dds_entity *e)
|
||||
{
|
||||
switch (e->m_kind)
|
||||
|
@ -110,7 +135,7 @@ static bool entity_has_status (const dds_entity *e)
|
|||
return false;
|
||||
}
|
||||
|
||||
dds_entity_t dds_entity_init (dds_entity *e, dds_entity *parent, dds_entity_kind_t kind, dds_qos_t *qos, const dds_listener_t *listener, status_mask_t mask)
|
||||
dds_entity_t dds_entity_init (dds_entity *e, dds_entity *parent, dds_entity_kind_t kind, bool implicit, dds_qos_t *qos, const dds_listener_t *listener, status_mask_t mask)
|
||||
{
|
||||
dds_handle_t handle;
|
||||
|
||||
|
@ -125,6 +150,8 @@ dds_entity_t dds_entity_init (dds_entity *e, dds_entity *parent, dds_entity_kind
|
|||
|
||||
/* TODO: CHAM-96: Implement dynamic enabling of entity. */
|
||||
e->m_flags |= DDS_ENTITY_ENABLED;
|
||||
if (implicit)
|
||||
e->m_flags |= DDS_ENTITY_IMPLICIT;
|
||||
|
||||
/* set the status enable based on kind */
|
||||
if (entity_has_status (e))
|
||||
|
@ -162,12 +189,14 @@ dds_entity_t dds_entity_init (dds_entity *e, dds_entity *parent, dds_entity_kind
|
|||
|
||||
if (kind == DDS_KIND_CYCLONEDDS)
|
||||
{
|
||||
if ((handle = dds_handle_register_special (&e->m_hdllink, DDS_CYCLONEDDS_HANDLE)) <= 0)
|
||||
if ((handle = dds_handle_register_special (&e->m_hdllink, implicit, true, DDS_CYCLONEDDS_HANDLE)) <= 0)
|
||||
return (dds_entity_t) handle;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((handle = dds_handle_create (&e->m_hdllink)) <= 0)
|
||||
/* for topics, refc counts readers/writers, for all others, it counts children (this we can get away with
|
||||
as long as topics can't have children) */
|
||||
if ((handle = dds_handle_create (&e->m_hdllink, implicit, (kind != DDS_KIND_TOPIC))) <= 0)
|
||||
return (dds_entity_t) handle;
|
||||
}
|
||||
|
||||
|
@ -182,22 +211,53 @@ void dds_entity_init_complete (dds_entity *entity)
|
|||
|
||||
void dds_entity_register_child (dds_entity *parent, dds_entity *child)
|
||||
{
|
||||
/* parent must be tracking children in its refc, or children can't be added */
|
||||
assert (ddsrt_atomic_ld32 (&parent->m_hdllink.cnt_flags) & HDL_FLAG_ALLOW_CHILDREN);
|
||||
assert (child->m_iid != 0);
|
||||
assert (ddsrt_avl_lookup (&dds_entity_children_td, &parent->m_children, &child->m_iid) == NULL);
|
||||
ddsrt_avl_insert (&dds_entity_children_td, &parent->m_children, child);
|
||||
dds_entity_add_ref_locked (parent);
|
||||
}
|
||||
|
||||
static dds_entity *next_non_topic_child (ddsrt_avl_tree_t *remaining_children)
|
||||
static dds_entity *get_first_child (ddsrt_avl_tree_t *remaining_children, bool ignore_topics)
|
||||
{
|
||||
ddsrt_avl_iter_t it;
|
||||
for (dds_entity *e = ddsrt_avl_iter_first (&dds_entity_children_td, remaining_children, &it); e != NULL; e = ddsrt_avl_iter_next (&it))
|
||||
{
|
||||
if (dds_entity_kind (e) != DDS_KIND_TOPIC)
|
||||
if ((!ignore_topics) || (dds_entity_kind(e) != DDS_KIND_TOPIC))
|
||||
return e;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void delete_children(struct dds_entity *parent, bool ignore_topics)
|
||||
{
|
||||
dds_entity *child;
|
||||
dds_return_t ret;
|
||||
ddsrt_mutex_lock (&parent->m_mutex);
|
||||
while ((child = get_first_child(&parent->m_children, ignore_topics)) != NULL)
|
||||
{
|
||||
dds_entity_t child_handle = child->m_hdllink.hdl;
|
||||
|
||||
/* The child will remove itself from the parent->m_children list. */
|
||||
ddsrt_mutex_unlock (&parent->m_mutex);
|
||||
ret = dds_delete_impl (child_handle, DIS_FROM_PARENT);
|
||||
assert (ret == DDS_RETCODE_OK || ret == DDS_RETCODE_BAD_PARAMETER);
|
||||
ddsrt_mutex_lock (&parent->m_mutex);
|
||||
|
||||
/* The dds_delete can fail if the child is being deleted in parallel,
|
||||
* in which case: wait when its not deleted yet.
|
||||
* The child will trigger the condition after it removed itself from
|
||||
* the childrens list. */
|
||||
if ((ret == DDS_RETCODE_BAD_PARAMETER) &&
|
||||
(get_first_child(&parent->m_children, ignore_topics) == child))
|
||||
{
|
||||
ddsrt_cond_wait (&parent->m_cond, &parent->m_mutex);
|
||||
}
|
||||
}
|
||||
ddsrt_mutex_unlock (&parent->m_mutex);
|
||||
}
|
||||
|
||||
#define TRACE_DELETE 0 /* FIXME: use DDS_LOG for this */
|
||||
#if TRACE_DELETE
|
||||
static const char *entity_kindstr (dds_entity_kind_t kind)
|
||||
|
@ -227,13 +287,11 @@ static void print_delete (const dds_entity *e, enum delete_impl_state delstate ,
|
|||
printf ("delete(%p, delstate %s, iid %"PRIx64"): %s%s %d pin %u refc %u %s %s\n",
|
||||
(void *) e, (delstate == DIS_IMPLICIT) ? "implicit" : (delstate == DIS_EXPLICIT) ? "explicit" : "from_parent", iid,
|
||||
entity_kindstr (e->m_kind), (e->m_flags & DDS_ENTITY_IMPLICIT) ? " [implicit]" : "",
|
||||
e->m_hdllink.hdl, cm & 0xfff, (cm >> 12) & 0xffff, (cm & 0x80000000) ? "closed" : "open",
|
||||
e->m_hdllink.hdl, cm & 0xfff, (cm >> 12) & 0x7fff, (cm & 0x80000000) ? "closed" : "open",
|
||||
ddsrt_avl_is_empty (&e->m_children) ? "childless" : "has-children");
|
||||
}
|
||||
#endif
|
||||
|
||||
static dds_return_t dds_delete_impl (dds_entity_t entity, enum delete_impl_state delstate);
|
||||
|
||||
dds_return_t dds_delete (dds_entity_t entity)
|
||||
{
|
||||
return dds_delete_impl (entity, DIS_EXPLICIT);
|
||||
|
@ -252,53 +310,33 @@ static dds_return_t dds_delete_impl (dds_entity_t entity, enum delete_impl_state
|
|||
{
|
||||
dds_entity *e;
|
||||
dds_return_t ret;
|
||||
if ((ret = dds_entity_pin (entity, &e)) < 0)
|
||||
return ret;
|
||||
else
|
||||
if ((ret = dds_entity_pin_for_delete (entity, (delstate != DIS_IMPLICIT), &e)) == DDS_RETCODE_OK)
|
||||
return dds_delete_impl_pinned (e, delstate);
|
||||
else if (ret == DDS_RETCODE_TRY_AGAIN) /* non-child refs exist */
|
||||
return DDS_RETCODE_OK;
|
||||
else
|
||||
return ret;
|
||||
}
|
||||
|
||||
dds_return_t dds_delete_impl_pinned (dds_entity *e, enum delete_impl_state delstate)
|
||||
{
|
||||
dds_entity *child;
|
||||
dds_return_t ret;
|
||||
|
||||
/* Any number of threads pinning it, possibly in delete, or having pinned it and
|
||||
trying to acquire m_mutex */
|
||||
|
||||
ddsrt_mutex_lock (&e->m_mutex);
|
||||
#if TRACE_DELETE
|
||||
print_delete (e, delstate, iid);
|
||||
print_delete (e, delstate, e->m_iid);
|
||||
#endif
|
||||
|
||||
/* If another thread was racing us in delete, it will have set the CLOSING flag
|
||||
while holding m_mutex and we had better bail out. */
|
||||
if (dds_handle_is_closed (&e->m_hdllink))
|
||||
{
|
||||
dds_entity_unlock (e);
|
||||
return DDS_RETCODE_OK;
|
||||
}
|
||||
assert (dds_handle_is_closed (&e->m_hdllink));
|
||||
return really_delete_pinned_closed_locked (e, delstate);
|
||||
}
|
||||
|
||||
/* Ignore children calling up to delete an implicit parent if there are still
|
||||
(or again) children */
|
||||
if (delstate == DIS_IMPLICIT)
|
||||
{
|
||||
if (!((e->m_flags & DDS_ENTITY_IMPLICIT) && ddsrt_avl_is_empty (&e->m_children)))
|
||||
{
|
||||
dds_entity_unlock (e);
|
||||
return DDS_RETCODE_OK;
|
||||
}
|
||||
}
|
||||
|
||||
/* Drop reference, atomically setting CLOSING if no other references remain.
|
||||
FIXME: that's not quite right: this is really only for topics. After a call
|
||||
to delete, the handle ought to become invalid even if the topic stays (and
|
||||
should perhaps even be revivable via find_topic). */
|
||||
if (! dds_handle_drop_ref (&e->m_hdllink))
|
||||
{
|
||||
dds_entity_unlock (e);
|
||||
return DDS_RETCODE_OK;
|
||||
}
|
||||
static dds_return_t really_delete_pinned_closed_locked (struct dds_entity *e, enum delete_impl_state delstate)
|
||||
{
|
||||
dds_return_t ret;
|
||||
|
||||
/* No threads pinning it anymore, no need to worry about other threads deleting
|
||||
it, but there can still be plenty of threads that have it pinned and are
|
||||
|
@ -354,24 +392,8 @@ dds_return_t dds_delete_impl_pinned (dds_entity *e, enum delete_impl_state delst
|
|||
*
|
||||
* To circumvent the problem. We ignore topics in the first loop.
|
||||
*/
|
||||
ddsrt_mutex_lock (&e->m_mutex);
|
||||
while ((child = next_non_topic_child (&e->m_children)) != NULL)
|
||||
{
|
||||
/* FIXME: dds_delete can fail if the child is being deleted in parallel, in which case: wait */
|
||||
dds_entity_t child_handle = child->m_hdllink.hdl;
|
||||
ddsrt_mutex_unlock (&e->m_mutex);
|
||||
(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)
|
||||
{
|
||||
assert (dds_entity_kind (child) == DDS_KIND_TOPIC);
|
||||
dds_entity_t child_handle = child->m_hdllink.hdl;
|
||||
ddsrt_mutex_unlock (&e->m_mutex);
|
||||
(void) dds_delete_impl (child_handle, DIS_FROM_PARENT);
|
||||
ddsrt_mutex_lock (&e->m_mutex);
|
||||
}
|
||||
ddsrt_mutex_unlock (&e->m_mutex);
|
||||
delete_children(e, true /* ignore topics */);
|
||||
delete_children(e, false /* delete topics */);
|
||||
|
||||
/* The dds_handle_delete will wait until the last active claim on that handle is
|
||||
released. It is possible that this last release will be done by a thread that was
|
||||
|
@ -391,15 +413,16 @@ dds_return_t dds_delete_impl_pinned (dds_entity *e, enum delete_impl_state delst
|
|||
ddsrt_mutex_lock (&p->m_mutex);
|
||||
assert (ddsrt_avl_lookup (&dds_entity_children_td, &p->m_children, &e->m_iid) != NULL);
|
||||
ddsrt_avl_delete (&dds_entity_children_td, &p->m_children, e);
|
||||
if (dds_handle_drop_childref_and_pin (&p->m_hdllink, delstate != DIS_FROM_PARENT))
|
||||
{
|
||||
dds_handle_close(&p->m_hdllink);
|
||||
assert (dds_handle_is_closed (&p->m_hdllink));
|
||||
assert (dds_handle_is_not_refd (&p->m_hdllink));
|
||||
assert (ddsrt_avl_is_empty (&p->m_children));
|
||||
parent_to_delete = p;
|
||||
}
|
||||
/* trigger parent in case it is waiting in delete */
|
||||
ddsrt_cond_broadcast (&p->m_cond);
|
||||
|
||||
if (delstate != DIS_FROM_PARENT && (p->m_flags & DDS_ENTITY_IMPLICIT) && ddsrt_avl_is_empty (&p->m_children))
|
||||
{
|
||||
if ((ret = dds_entity_pin (p->m_hdllink.hdl, &parent_to_delete)) < 0)
|
||||
parent_to_delete = NULL;
|
||||
}
|
||||
|
||||
ddsrt_mutex_unlock (&p->m_mutex);
|
||||
}
|
||||
|
||||
|
@ -1121,6 +1144,19 @@ dds_return_t dds_entity_pin (dds_entity_t hdl, dds_entity **eptr)
|
|||
}
|
||||
}
|
||||
|
||||
dds_return_t dds_entity_pin_for_delete (dds_entity_t hdl, bool explicit, dds_entity **eptr)
|
||||
{
|
||||
dds_return_t hres;
|
||||
struct dds_handle_link *hdllink;
|
||||
if ((hres = dds_handle_pin_for_delete (hdl, explicit, &hdllink)) < 0)
|
||||
return hres;
|
||||
else
|
||||
{
|
||||
*eptr = dds_entity_from_handle_link (hdllink);
|
||||
return DDS_RETCODE_OK;
|
||||
}
|
||||
}
|
||||
|
||||
void dds_entity_unpin (dds_entity *e)
|
||||
{
|
||||
dds_handle_unpin (&e->m_hdllink);
|
||||
|
@ -1349,3 +1385,32 @@ dds_return_t dds_generic_unimplemented_operation (dds_entity_t handle, dds_entit
|
|||
return dds_generic_unimplemented_operation_manykinds (handle, 1, &kind);
|
||||
}
|
||||
|
||||
dds_return_t dds_assert_liveliness (dds_entity_t entity)
|
||||
{
|
||||
dds_return_t rc;
|
||||
dds_entity *e, *ewr;
|
||||
|
||||
if ((rc = dds_entity_pin (entity, &e)) != DDS_RETCODE_OK)
|
||||
return rc;
|
||||
switch (dds_entity_kind (e))
|
||||
{
|
||||
case DDS_KIND_PARTICIPANT: {
|
||||
write_pmd_message_guid (&e->m_domain->gv, &e->m_guid, PARTICIPANT_MESSAGE_DATA_KIND_MANUAL_LIVELINESS_UPDATE);
|
||||
break;
|
||||
}
|
||||
case DDS_KIND_WRITER: {
|
||||
if ((rc = dds_entity_lock (entity, DDS_KIND_WRITER, &ewr)) != DDS_RETCODE_OK)
|
||||
return rc;
|
||||
if ((rc = write_hb_liveliness (&e->m_domain->gv, &e->m_guid, ((struct dds_writer *)ewr)->m_xp)) != DDS_RETCODE_OK)
|
||||
return rc;
|
||||
dds_entity_unlock (e);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
rc = DDS_RETCODE_ILLEGAL_OPERATION;
|
||||
break;
|
||||
}
|
||||
}
|
||||
dds_entity_unpin (e);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -57,18 +57,18 @@ dds_entity_t dds_create_guardcondition (dds_entity_t owner)
|
|||
}
|
||||
|
||||
dds_guardcond *gcond = dds_alloc (sizeof (*gcond));
|
||||
dds_entity_t hdl = dds_entity_init (&gcond->m_entity, e, DDS_KIND_COND_GUARD, NULL, NULL, 0);
|
||||
dds_entity_t hdl = dds_entity_init (&gcond->m_entity, e, DDS_KIND_COND_GUARD, false, NULL, NULL, 0);
|
||||
gcond->m_entity.m_iid = ddsi_iid_gen ();
|
||||
dds_entity_register_child (e, &gcond->m_entity);
|
||||
dds_entity_init_complete (&gcond->m_entity);
|
||||
dds_entity_unlock (e);
|
||||
dds_delete_impl_pinned (&dds_global.m_entity, DIS_EXPLICIT);
|
||||
dds_entity_unpin_and_drop_ref (&dds_global.m_entity);
|
||||
return hdl;
|
||||
|
||||
err_entity_kind:
|
||||
dds_entity_unlock (e);
|
||||
err_entity_lock:
|
||||
dds_delete_impl_pinned (&dds_global.m_entity, DIS_EXPLICIT);
|
||||
dds_entity_unpin_and_drop_ref (&dds_global.m_entity);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,11 +20,36 @@
|
|||
#include "dds__handles.h"
|
||||
#include "dds__types.h"
|
||||
|
||||
#define HDL_REFCOUNT_MASK (0x0ffff000u)
|
||||
#define HDL_REFCOUNT_MASK (0x07fff000u)
|
||||
#define HDL_REFCOUNT_UNIT (0x00001000u)
|
||||
#define HDL_REFCOUNT_SHIFT 12
|
||||
#define HDL_PINCOUNT_MASK (0x00000fffu)
|
||||
|
||||
/*
|
||||
"regular" entities other than topics:
|
||||
- create makes it
|
||||
- delete deletes it and its children immediately
|
||||
- explicit domain: additional protection for bootstrapping complications need extra care
|
||||
|
||||
implicit entities other than topics (pub, sub, domain, cyclonedds):
|
||||
- created "spontaneously" as a consequence of creating the writer/reader/participant
|
||||
- delete of last child causes it to disappear
|
||||
- explicit delete treated like a delete of a "regular" entity
|
||||
- domain, cyclonedds: bootstrapping complications require additional protection
|
||||
|
||||
topics:
|
||||
- create makes it
|
||||
- never has children (so the handle's cnt_flags can have a different meaning)
|
||||
- readers, writers keep it in existence
|
||||
- delete deferred until no readers/writers exist
|
||||
- an attempt at deleting it fails if in "deferred delete" state (or should it simply
|
||||
return ok while doing nothing?), other operations keep going so, e.g., listeners
|
||||
remain useful
|
||||
|
||||
built-in topics:
|
||||
- implicit variant of a topic
|
||||
*/
|
||||
|
||||
/* Maximum number of handles is INT32_MAX - 1, but as the allocator relies on a
|
||||
random generator for finding a free one, the time spent in the dds_handle_create
|
||||
increases with an increasing number of handles. 16M handles seems likely to be
|
||||
|
@ -82,7 +107,7 @@ void dds_handle_server_fini (void)
|
|||
cf & HDL_PINCOUNT_MASK, (cf & HDL_REFCOUNT_MASK) >> HDL_REFCOUNT_SHIFT,
|
||||
cf & HDL_FLAG_PENDING ? " pending" : "",
|
||||
cf & HDL_FLAG_CLOSING ? " closing" : "",
|
||||
cf & HDL_FLAG_CLOSED ? " closed" : "");
|
||||
cf & HDL_FLAG_DELETE_DEFERRED ? " delete-deferred" : "");
|
||||
}
|
||||
assert (ddsrt_hh_iter_first (handles.ht, &it) == NULL);
|
||||
#endif
|
||||
|
@ -94,9 +119,9 @@ void dds_handle_server_fini (void)
|
|||
}
|
||||
|
||||
static bool hhadd (struct ddsrt_hh *ht, void *elem) { return ddsrt_hh_add (ht, elem); }
|
||||
static dds_handle_t dds_handle_create_int (struct dds_handle_link *link)
|
||||
static dds_handle_t dds_handle_create_int (struct dds_handle_link *link, bool implicit, bool refc_counts_children)
|
||||
{
|
||||
ddsrt_atomic_st32 (&link->cnt_flags, HDL_FLAG_PENDING | HDL_REFCOUNT_UNIT | 1u);
|
||||
ddsrt_atomic_st32 (&link->cnt_flags, HDL_FLAG_PENDING | (implicit ? HDL_FLAG_IMPLICIT : HDL_REFCOUNT_UNIT) | (refc_counts_children ? HDL_FLAG_ALLOW_CHILDREN : 0) | 1u);
|
||||
do {
|
||||
do {
|
||||
link->hdl = (int32_t) (ddsrt_random () & INT32_MAX);
|
||||
|
@ -105,7 +130,7 @@ static dds_handle_t dds_handle_create_int (struct dds_handle_link *link)
|
|||
return link->hdl;
|
||||
}
|
||||
|
||||
dds_handle_t dds_handle_create (struct dds_handle_link *link)
|
||||
dds_handle_t dds_handle_create (struct dds_handle_link *link, bool implicit, bool allow_children)
|
||||
{
|
||||
dds_handle_t ret;
|
||||
ddsrt_mutex_lock (&handles.lock);
|
||||
|
@ -117,14 +142,14 @@ dds_handle_t dds_handle_create (struct dds_handle_link *link)
|
|||
else
|
||||
{
|
||||
handles.count++;
|
||||
ret = dds_handle_create_int (link);
|
||||
ret = dds_handle_create_int (link, implicit, allow_children);
|
||||
ddsrt_mutex_unlock (&handles.lock);
|
||||
assert (ret > 0);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
dds_return_t dds_handle_register_special (struct dds_handle_link *link, dds_handle_t handle)
|
||||
dds_return_t dds_handle_register_special (struct dds_handle_link *link, bool implicit, bool allow_children, dds_handle_t handle)
|
||||
{
|
||||
dds_return_t ret;
|
||||
if (handle <= 0)
|
||||
|
@ -138,7 +163,7 @@ dds_return_t dds_handle_register_special (struct dds_handle_link *link, dds_hand
|
|||
else
|
||||
{
|
||||
handles.count++;
|
||||
ddsrt_atomic_st32 (&link->cnt_flags, HDL_FLAG_PENDING | HDL_REFCOUNT_UNIT | 1u);
|
||||
ddsrt_atomic_st32 (&link->cnt_flags, HDL_FLAG_PENDING | (implicit ? HDL_FLAG_IMPLICIT : HDL_REFCOUNT_UNIT) | (allow_children ? HDL_FLAG_ALLOW_CHILDREN : 0) | 1u);
|
||||
link->hdl = handle;
|
||||
if (hhadd (handles.ht, link))
|
||||
ret = handle;
|
||||
|
@ -155,9 +180,9 @@ void dds_handle_unpend (struct dds_handle_link *link)
|
|||
#ifndef NDEBUG
|
||||
uint32_t cf = ddsrt_atomic_ld32 (&link->cnt_flags);
|
||||
assert ((cf & HDL_FLAG_PENDING));
|
||||
assert (!(cf & HDL_FLAG_CLOSED));
|
||||
assert (!(cf & HDL_FLAG_DELETE_DEFERRED));
|
||||
assert (!(cf & HDL_FLAG_CLOSING));
|
||||
assert ((cf & HDL_REFCOUNT_MASK) >= HDL_REFCOUNT_UNIT);
|
||||
assert ((cf & HDL_REFCOUNT_MASK) >= HDL_REFCOUNT_UNIT || (cf & HDL_FLAG_IMPLICIT));
|
||||
assert ((cf & HDL_PINCOUNT_MASK) >= 1u);
|
||||
#endif
|
||||
ddsrt_atomic_and32 (&link->cnt_flags, ~HDL_FLAG_PENDING);
|
||||
|
@ -171,7 +196,6 @@ int32_t dds_handle_delete (struct dds_handle_link *link)
|
|||
if (!(cf & HDL_FLAG_PENDING))
|
||||
{
|
||||
assert (cf & HDL_FLAG_CLOSING);
|
||||
assert (cf & HDL_FLAG_CLOSED);
|
||||
assert ((cf & HDL_REFCOUNT_MASK) == 0u);
|
||||
}
|
||||
assert ((cf & HDL_PINCOUNT_MASK) == 1u);
|
||||
|
@ -213,7 +237,7 @@ static int32_t dds_handle_pin_int (dds_handle_t hdl, uint32_t delta, struct dds_
|
|||
rc = DDS_RETCODE_OK;
|
||||
do {
|
||||
cf = ddsrt_atomic_ld32 (&(*link)->cnt_flags);
|
||||
if (cf & (HDL_FLAG_CLOSED | HDL_FLAG_CLOSING | HDL_FLAG_PENDING))
|
||||
if (cf & (HDL_FLAG_CLOSING | HDL_FLAG_PENDING))
|
||||
{
|
||||
rc = DDS_RETCODE_BAD_PARAMETER;
|
||||
break;
|
||||
|
@ -229,6 +253,169 @@ int32_t dds_handle_pin (dds_handle_t hdl, struct dds_handle_link **link)
|
|||
return dds_handle_pin_int (hdl, 1u, link);
|
||||
}
|
||||
|
||||
int32_t dds_handle_pin_for_delete (dds_handle_t hdl, bool explicit, struct dds_handle_link **link)
|
||||
{
|
||||
struct dds_handle_link dummy = { .hdl = hdl };
|
||||
int32_t rc;
|
||||
/* it makes sense to check here for initialization: the first thing any operation
|
||||
(other than create_participant) does is to call dds_handle_pin on the supplied
|
||||
entity, so checking here whether the library has been initialised helps avoid
|
||||
crashes if someone forgets to create a participant (or allows a program to
|
||||
continue after failing to create one).
|
||||
|
||||
One could check that the handle is > 0, but that would catch fewer errors
|
||||
without any advantages. */
|
||||
if (handles.ht == NULL)
|
||||
return DDS_RETCODE_PRECONDITION_NOT_MET;
|
||||
|
||||
ddsrt_mutex_lock (&handles.lock);
|
||||
*link = ddsrt_hh_lookup (handles.ht, &dummy);
|
||||
if (*link == NULL)
|
||||
rc = DDS_RETCODE_BAD_PARAMETER;
|
||||
else
|
||||
{
|
||||
uint32_t cf, cf1;
|
||||
/* Assume success; bail out if the object turns out to be in the process of
|
||||
being deleted */
|
||||
do {
|
||||
cf = ddsrt_atomic_ld32 (&(*link)->cnt_flags);
|
||||
|
||||
if (cf & (HDL_FLAG_CLOSING | HDL_FLAG_PENDING))
|
||||
{
|
||||
/* Only one can succeed (and if closing is already set, the handle's reference has
|
||||
already been dropped) */
|
||||
rc = DDS_RETCODE_BAD_PARAMETER;
|
||||
break;
|
||||
}
|
||||
else if (cf & HDL_FLAG_DELETE_DEFERRED)
|
||||
{
|
||||
/* Someone already called delete, but the operation was deferred becauses there are still
|
||||
outstanding references. This implies that there are no children, because then the
|
||||
entire hierarchy would simply have been deleted. */
|
||||
assert (!(cf & HDL_FLAG_ALLOW_CHILDREN));
|
||||
if (cf & HDL_REFCOUNT_MASK)
|
||||
{
|
||||
rc = DDS_RETCODE_ALREADY_DELETED;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Refcount reached zero. Pin to allow deletion. */
|
||||
cf1 = (cf + 1u) | HDL_FLAG_CLOSING;
|
||||
}
|
||||
}
|
||||
else if (explicit)
|
||||
{
|
||||
/* Explicit call to dds_delete (either by application or by parent deleting its children) */
|
||||
if (cf & HDL_FLAG_IMPLICIT)
|
||||
{
|
||||
/* Entity is implicit, so handle doesn't hold a reference */
|
||||
cf1 = (cf + 1u) | HDL_FLAG_CLOSING;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert ((cf & HDL_REFCOUNT_MASK) > 0);
|
||||
if ((cf & HDL_REFCOUNT_MASK) == HDL_REFCOUNT_UNIT)
|
||||
{
|
||||
/* Last reference is closing. Pin entity and indicate that it is closing. */
|
||||
cf1 = (cf - HDL_REFCOUNT_UNIT + 1u) | HDL_FLAG_CLOSING;
|
||||
}
|
||||
else if (!(cf & HDL_FLAG_ALLOW_CHILDREN))
|
||||
{
|
||||
/* The refcnt does not contain children.
|
||||
* Indicate that the closing of the entity is deferred. */
|
||||
cf1 = (cf - HDL_REFCOUNT_UNIT) | HDL_FLAG_DELETE_DEFERRED;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Entity is explicit, so handle held a reference, refc only counts children as so is not our concern */
|
||||
cf1 = (cf - HDL_REFCOUNT_UNIT + 1u) | HDL_FLAG_CLOSING;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Implicit call to dds_delete (child invoking delete on its parent) */
|
||||
if (cf & HDL_FLAG_IMPLICIT)
|
||||
{
|
||||
assert ((cf & HDL_REFCOUNT_MASK) > 0);
|
||||
if ((cf & HDL_REFCOUNT_MASK) == HDL_REFCOUNT_UNIT)
|
||||
{
|
||||
/* Last reference is closing. Pin entity and indicate that it is closing. */
|
||||
cf1 = (cf - HDL_REFCOUNT_UNIT + 1u) | HDL_FLAG_CLOSING;
|
||||
}
|
||||
else if (!(cf & HDL_FLAG_ALLOW_CHILDREN))
|
||||
{
|
||||
/* The refcnt does not contain children.
|
||||
* Indicate that the closing of the entity is deferred. */
|
||||
cf1 = (cf - HDL_REFCOUNT_UNIT) | HDL_FLAG_DELETE_DEFERRED;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Just reduce the children refcount by one. */
|
||||
cf1 = (cf - HDL_REFCOUNT_UNIT);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Child can't delete an explicit parent */
|
||||
rc = DDS_RETCODE_ILLEGAL_OPERATION;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
rc = ((cf1 & HDL_REFCOUNT_MASK) == 0 || (cf1 & HDL_FLAG_ALLOW_CHILDREN)) ? DDS_RETCODE_OK : DDS_RETCODE_TRY_AGAIN;
|
||||
} while (!ddsrt_atomic_cas32 (&(*link)->cnt_flags, cf, cf1));
|
||||
}
|
||||
ddsrt_mutex_unlock (&handles.lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
bool dds_handle_drop_childref_and_pin (struct dds_handle_link *link, bool may_delete_parent)
|
||||
{
|
||||
bool del_parent = false;
|
||||
ddsrt_mutex_lock (&handles.lock);
|
||||
uint32_t cf, cf1;
|
||||
do {
|
||||
cf = ddsrt_atomic_ld32 (&link->cnt_flags);
|
||||
|
||||
if (cf & (HDL_FLAG_CLOSING | HDL_FLAG_PENDING))
|
||||
{
|
||||
/* Only one can succeed; child ref still to be removed */
|
||||
assert ((cf & HDL_REFCOUNT_MASK) > 0);
|
||||
cf1 = (cf - HDL_REFCOUNT_UNIT);
|
||||
del_parent = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cf & HDL_FLAG_IMPLICIT)
|
||||
{
|
||||
/* Implicit parent: delete if last ref */
|
||||
if ((cf & HDL_REFCOUNT_MASK) == HDL_REFCOUNT_UNIT && may_delete_parent)
|
||||
{
|
||||
cf1 = (cf - HDL_REFCOUNT_UNIT + 1u);
|
||||
del_parent = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert ((cf & HDL_REFCOUNT_MASK) > 0);
|
||||
cf1 = (cf - HDL_REFCOUNT_UNIT);
|
||||
del_parent = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Child can't delete an explicit parent; child ref still to be removed */
|
||||
assert ((cf & HDL_REFCOUNT_MASK) > 0);
|
||||
cf1 = (cf - HDL_REFCOUNT_UNIT);
|
||||
del_parent = false;
|
||||
}
|
||||
}
|
||||
} while (!ddsrt_atomic_cas32 (&link->cnt_flags, cf, cf1));
|
||||
ddsrt_mutex_unlock (&handles.lock);
|
||||
return del_parent;
|
||||
}
|
||||
|
||||
int32_t dds_handle_pin_and_ref (dds_handle_t hdl, struct dds_handle_link **link)
|
||||
{
|
||||
return dds_handle_pin_int (hdl, HDL_REFCOUNT_UNIT + 1u, link);
|
||||
|
@ -237,7 +424,6 @@ int32_t dds_handle_pin_and_ref (dds_handle_t hdl, struct dds_handle_link **link)
|
|||
void dds_handle_repin (struct dds_handle_link *link)
|
||||
{
|
||||
uint32_t x = ddsrt_atomic_inc32_nv (&link->cnt_flags);
|
||||
assert (!(x & HDL_FLAG_CLOSED));
|
||||
(void) x;
|
||||
}
|
||||
|
||||
|
@ -245,7 +431,6 @@ void dds_handle_unpin (struct dds_handle_link *link)
|
|||
{
|
||||
#ifndef NDEBUG
|
||||
uint32_t cf = ddsrt_atomic_ld32 (&link->cnt_flags);
|
||||
assert (!(cf & HDL_FLAG_CLOSED));
|
||||
if (cf & HDL_FLAG_CLOSING)
|
||||
assert ((cf & HDL_PINCOUNT_MASK) > 1u);
|
||||
else
|
||||
|
@ -266,16 +451,43 @@ void dds_handle_add_ref (struct dds_handle_link *link)
|
|||
|
||||
bool dds_handle_drop_ref (struct dds_handle_link *link)
|
||||
{
|
||||
assert ((ddsrt_atomic_ld32 (&link->cnt_flags) & HDL_REFCOUNT_MASK) != 0);
|
||||
uint32_t old, new;
|
||||
do {
|
||||
old = ddsrt_atomic_ld32 (&link->cnt_flags);
|
||||
if ((old & HDL_REFCOUNT_MASK) != HDL_REFCOUNT_UNIT)
|
||||
new = old - HDL_REFCOUNT_UNIT;
|
||||
else
|
||||
new = (old - HDL_REFCOUNT_UNIT) | HDL_FLAG_CLOSING;
|
||||
assert ((old & HDL_REFCOUNT_MASK) > 0);
|
||||
new = old - HDL_REFCOUNT_UNIT;
|
||||
} while (!ddsrt_atomic_cas32 (&link->cnt_flags, old, new));
|
||||
return (new & HDL_REFCOUNT_MASK) == 0;
|
||||
ddsrt_mutex_lock (&handles.lock);
|
||||
if ((new & (HDL_FLAG_CLOSING | HDL_PINCOUNT_MASK)) == (HDL_FLAG_CLOSING | 1u))
|
||||
{
|
||||
ddsrt_cond_broadcast (&handles.cond);
|
||||
}
|
||||
ddsrt_mutex_unlock (&handles.lock);
|
||||
return ((new & HDL_REFCOUNT_MASK) == 0);
|
||||
}
|
||||
|
||||
bool dds_handle_unpin_and_drop_ref (struct dds_handle_link *link)
|
||||
{
|
||||
uint32_t old, new;
|
||||
do {
|
||||
old = ddsrt_atomic_ld32 (&link->cnt_flags);
|
||||
assert ((old & HDL_REFCOUNT_MASK) > 0);
|
||||
assert ((old & HDL_PINCOUNT_MASK) > 0);
|
||||
new = old - HDL_REFCOUNT_UNIT - 1u;
|
||||
} while (!ddsrt_atomic_cas32 (&link->cnt_flags, old, new));
|
||||
ddsrt_mutex_lock (&handles.lock);
|
||||
if ((new & (HDL_FLAG_CLOSING | HDL_PINCOUNT_MASK)) == (HDL_FLAG_CLOSING | 1u))
|
||||
{
|
||||
ddsrt_cond_broadcast (&handles.cond);
|
||||
}
|
||||
ddsrt_mutex_unlock (&handles.lock);
|
||||
return ((new & HDL_REFCOUNT_MASK) == 0);
|
||||
}
|
||||
|
||||
bool dds_handle_close (struct dds_handle_link *link)
|
||||
{
|
||||
uint32_t old = ddsrt_atomic_or32_ov (&link->cnt_flags, HDL_FLAG_CLOSING);
|
||||
return (old & HDL_REFCOUNT_MASK) == 0;
|
||||
}
|
||||
|
||||
void dds_handle_close_wait (struct dds_handle_link *link)
|
||||
|
@ -283,17 +495,18 @@ void dds_handle_close_wait (struct dds_handle_link *link)
|
|||
#ifndef NDEBUG
|
||||
uint32_t cf = ddsrt_atomic_ld32 (&link->cnt_flags);
|
||||
assert ((cf & HDL_FLAG_CLOSING));
|
||||
assert (!(cf & HDL_FLAG_CLOSED));
|
||||
assert ((cf & HDL_REFCOUNT_MASK) == 0u);
|
||||
assert ((cf & HDL_PINCOUNT_MASK) >= 1u);
|
||||
#endif
|
||||
ddsrt_mutex_lock (&handles.lock);
|
||||
while ((ddsrt_atomic_ld32 (&link->cnt_flags) & HDL_PINCOUNT_MASK) != 1u)
|
||||
ddsrt_cond_wait (&handles.cond, &handles.lock);
|
||||
/* only one thread may call close_wait on a given handle */
|
||||
assert (!(ddsrt_atomic_ld32 (&link->cnt_flags) & HDL_FLAG_CLOSED));
|
||||
ddsrt_atomic_or32 (&link->cnt_flags, HDL_FLAG_CLOSED);
|
||||
ddsrt_mutex_unlock (&handles.lock);
|
||||
}
|
||||
|
||||
bool dds_handle_is_not_refd (struct dds_handle_link *link)
|
||||
{
|
||||
return ((ddsrt_atomic_ld32 (&link->cnt_flags) & HDL_REFCOUNT_MASK) == 0);
|
||||
}
|
||||
|
||||
extern inline bool dds_handle_is_closed (struct dds_handle_link *link);
|
||||
|
|
|
@ -119,9 +119,8 @@ dds_return_t dds_init (void)
|
|||
goto fail_handleserver;
|
||||
}
|
||||
|
||||
dds_entity_init (&dds_global.m_entity, NULL, DDS_KIND_CYCLONEDDS, NULL, NULL, 0);
|
||||
dds_entity_init (&dds_global.m_entity, NULL, DDS_KIND_CYCLONEDDS, true, NULL, NULL, 0);
|
||||
dds_global.m_entity.m_iid = ddsi_iid_gen ();
|
||||
dds_global.m_entity.m_flags = DDS_ENTITY_IMPLICIT;
|
||||
dds_handle_repin (&dds_global.m_entity.m_hdllink);
|
||||
dds_entity_add_ref_locked (&dds_global.m_entity);
|
||||
dds_entity_init_complete (&dds_global.m_entity);
|
||||
|
|
|
@ -113,7 +113,7 @@ dds_return_t dds_unregister_instance_ts (dds_entity_t writer, const void *data,
|
|||
return ret;
|
||||
|
||||
if (wr->m_entity.m_qos)
|
||||
dds_qget_writer_data_lifecycle (wr->m_entity.m_qos, &autodispose);
|
||||
(void) dds_qget_writer_data_lifecycle (wr->m_entity.m_qos, &autodispose);
|
||||
|
||||
thread_state_awake (ts1, &wr->m_entity.m_domain->gv);
|
||||
if (autodispose)
|
||||
|
@ -140,7 +140,7 @@ dds_return_t dds_unregister_instance_ih_ts (dds_entity_t writer, dds_instance_ha
|
|||
return ret;
|
||||
|
||||
if (wr->m_entity.m_qos)
|
||||
dds_qget_writer_data_lifecycle (wr->m_entity.m_qos, &autodispose);
|
||||
(void) dds_qget_writer_data_lifecycle (wr->m_entity.m_qos, &autodispose);
|
||||
|
||||
thread_state_awake (ts1, &wr->m_entity.m_domain->gv);
|
||||
if (autodispose)
|
||||
|
|
|
@ -117,7 +117,7 @@ dds_entity_t dds_create_participant (const dds_domainid_t domain, const dds_qos_
|
|||
}
|
||||
|
||||
pp = dds_alloc (sizeof (*pp));
|
||||
if ((ret = dds_entity_init (&pp->m_entity, &dom->m_entity, DDS_KIND_PARTICIPANT, new_qos, listener, DDS_PARTICIPANT_STATUS_MASK)) < 0)
|
||||
if ((ret = dds_entity_init (&pp->m_entity, &dom->m_entity, DDS_KIND_PARTICIPANT, false, new_qos, listener, DDS_PARTICIPANT_STATUS_MASK)) < 0)
|
||||
goto err_entity_init;
|
||||
|
||||
pp->m_entity.m_guid = guid;
|
||||
|
@ -126,14 +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_entity.m_mutex);
|
||||
ddsrt_mutex_lock (&dom->m_entity.m_mutex);
|
||||
dds_entity_register_child (&dom->m_entity, &pp->m_entity);
|
||||
ddsrt_mutex_unlock (&dds_global.m_entity.m_mutex);
|
||||
ddsrt_mutex_unlock (&dom->m_entity.m_mutex);
|
||||
|
||||
dds_entity_init_complete (&pp->m_entity);
|
||||
/* drop temporary extra ref to domain, dds_init */
|
||||
dds_delete (dom->m_entity.m_hdllink.hdl);
|
||||
dds_delete_impl_pinned (&dds_global.m_entity, DIS_EXPLICIT);
|
||||
dds_entity_unpin_and_drop_ref (&dom->m_entity);
|
||||
dds_entity_unpin_and_drop_ref (&dds_global.m_entity);
|
||||
return ret;
|
||||
|
||||
err_entity_init:
|
||||
|
@ -141,9 +141,9 @@ err_entity_init:
|
|||
err_new_participant:
|
||||
err_qos_validation:
|
||||
dds_delete_qos (new_qos);
|
||||
dds_delete (dom->m_entity.m_hdllink.hdl);
|
||||
dds_entity_unpin_and_drop_ref (&dom->m_entity);
|
||||
err_domain_create:
|
||||
dds_delete_impl_pinned (&dds_global.m_entity, DIS_EXPLICIT);
|
||||
dds_entity_unpin_and_drop_ref (&dds_global.m_entity);
|
||||
err_dds_init:
|
||||
return ret;
|
||||
}
|
||||
|
@ -175,6 +175,6 @@ dds_return_t dds_lookup_participant (dds_domainid_t domain_id, dds_entity_t *par
|
|||
}
|
||||
}
|
||||
ddsrt_mutex_unlock (&dds_global.m_mutex);
|
||||
dds_delete_impl_pinned (&dds_global.m_entity, DIS_EXPLICIT);
|
||||
dds_entity_unpin_and_drop_ref (&dds_global.m_entity);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -45,17 +45,13 @@ const struct dds_entity_deriver dds_entity_deriver_publisher = {
|
|||
.validate_status = dds_publisher_status_validate
|
||||
};
|
||||
|
||||
dds_entity_t dds_create_publisher (dds_entity_t participant, const dds_qos_t *qos, const dds_listener_t *listener)
|
||||
dds_entity_t dds__create_publisher_l (dds_participant *par, bool implicit, const dds_qos_t *qos, const dds_listener_t *listener)
|
||||
{
|
||||
dds_participant *par;
|
||||
dds_publisher *pub;
|
||||
dds_entity_t hdl;
|
||||
dds_qos_t *new_qos;
|
||||
dds_return_t ret;
|
||||
|
||||
if ((ret = dds_participant_lock (participant, &par)) != DDS_RETCODE_OK)
|
||||
return ret;
|
||||
|
||||
new_qos = dds_create_qos ();
|
||||
if (qos)
|
||||
nn_xqos_mergein_missing (new_qos, qos, DDS_PUBLISHER_QOS_MASK);
|
||||
|
@ -67,10 +63,21 @@ dds_entity_t dds_create_publisher (dds_entity_t participant, const dds_qos_t *qo
|
|||
}
|
||||
|
||||
pub = dds_alloc (sizeof (*pub));
|
||||
hdl = dds_entity_init (&pub->m_entity, &par->m_entity, DDS_KIND_PUBLISHER, new_qos, listener, DDS_PUBLISHER_STATUS_MASK);
|
||||
hdl = dds_entity_init (&pub->m_entity, &par->m_entity, DDS_KIND_PUBLISHER, implicit, new_qos, listener, DDS_PUBLISHER_STATUS_MASK);
|
||||
pub->m_entity.m_iid = ddsi_iid_gen ();
|
||||
dds_entity_register_child (&par->m_entity, &pub->m_entity);
|
||||
dds_entity_init_complete (&pub->m_entity);
|
||||
return hdl;
|
||||
}
|
||||
|
||||
dds_entity_t dds_create_publisher (dds_entity_t participant, const dds_qos_t *qos, const dds_listener_t *listener)
|
||||
{
|
||||
dds_participant *par;
|
||||
dds_entity_t hdl;
|
||||
dds_return_t ret;
|
||||
if ((ret = dds_participant_lock (participant, &par)) != DDS_RETCODE_OK)
|
||||
return ret;
|
||||
hdl = dds__create_publisher_l (par, false, qos, listener);
|
||||
dds_participant_unlock (par);
|
||||
return hdl;
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ dds_readcond *dds_create_readcond (dds_reader *rd, dds_entity_kind_t kind, uint3
|
|||
{
|
||||
dds_readcond *cond = dds_alloc (sizeof (*cond));
|
||||
assert ((kind == DDS_KIND_COND_READ && filter == 0) || (kind == DDS_KIND_COND_QUERY && filter != 0));
|
||||
(void) dds_entity_init (&cond->m_entity, &rd->m_entity, kind, NULL, NULL, 0);
|
||||
(void) dds_entity_init (&cond->m_entity, &rd->m_entity, kind, false, NULL, NULL, 0);
|
||||
cond->m_entity.m_iid = ddsi_iid_gen ();
|
||||
dds_entity_register_child (&rd->m_entity, &cond->m_entity);
|
||||
cond->m_sample_states = mask & DDS_ANY_SAMPLE_STATE;
|
||||
|
|
|
@ -62,11 +62,11 @@ static dds_return_t dds_reader_delete (dds_entity *e) ddsrt_nonnull_all;
|
|||
static dds_return_t dds_reader_delete (dds_entity *e)
|
||||
{
|
||||
dds_reader * const rd = (dds_reader *) e;
|
||||
(void) dds_delete (rd->m_topic->m_entity.m_hdllink.hdl);
|
||||
dds_free (rd->m_loan);
|
||||
thread_state_awake (lookup_thread_state (), &e->m_domain->gv);
|
||||
dds_rhc_free (rd->m_rhc);
|
||||
thread_state_asleep (lookup_thread_state ());
|
||||
dds_entity_drop_ref (&rd->m_topic->m_entity);
|
||||
return DDS_RETCODE_OK;
|
||||
}
|
||||
|
||||
|
@ -150,6 +150,7 @@ void dds_reader_data_available_cb (struct dds_reader *rd)
|
|||
|
||||
rd->m_entity.m_cb_count--;
|
||||
rd->m_entity.m_cb_pending_count--;
|
||||
|
||||
ddsrt_cond_broadcast (&rd->m_entity.m_observers_cond);
|
||||
ddsrt_mutex_unlock (&rd->m_entity.m_observers_lock);
|
||||
}
|
||||
|
@ -232,16 +233,47 @@ void dds_reader_status_cb (void *ventity, const status_cb_data_t *data)
|
|||
}
|
||||
case DDS_LIVELINESS_CHANGED_STATUS_ID: {
|
||||
struct dds_liveliness_changed_status * const st = vst = &rd->m_liveliness_changed_status;
|
||||
if (data->add) {
|
||||
st->alive_count++;
|
||||
st->alive_count_change++;
|
||||
if (st->not_alive_count > 0) {
|
||||
DDSRT_STATIC_ASSERT ((uint32_t) LIVELINESS_CHANGED_ADD_ALIVE == 0 &&
|
||||
LIVELINESS_CHANGED_ADD_ALIVE < LIVELINESS_CHANGED_ADD_NOT_ALIVE &&
|
||||
LIVELINESS_CHANGED_ADD_NOT_ALIVE < LIVELINESS_CHANGED_REMOVE_NOT_ALIVE &&
|
||||
LIVELINESS_CHANGED_REMOVE_NOT_ALIVE < LIVELINESS_CHANGED_REMOVE_ALIVE &&
|
||||
LIVELINESS_CHANGED_REMOVE_ALIVE < LIVELINESS_CHANGED_ALIVE_TO_NOT_ALIVE &&
|
||||
LIVELINESS_CHANGED_ALIVE_TO_NOT_ALIVE < LIVELINESS_CHANGED_NOT_ALIVE_TO_ALIVE &&
|
||||
LIVELINESS_CHANGED_NOT_ALIVE_TO_ALIVE < LIVELINESS_CHANGED_TWITCH &&
|
||||
(uint32_t) LIVELINESS_CHANGED_TWITCH < UINT32_MAX);
|
||||
assert (data->extra <= (uint32_t) LIVELINESS_CHANGED_TWITCH);
|
||||
switch ((enum liveliness_changed_data_extra) data->extra)
|
||||
{
|
||||
case LIVELINESS_CHANGED_ADD_ALIVE:
|
||||
st->alive_count++;
|
||||
st->alive_count_change++;
|
||||
break;
|
||||
case LIVELINESS_CHANGED_ADD_NOT_ALIVE:
|
||||
st->not_alive_count++;
|
||||
st->not_alive_count_change++;
|
||||
break;
|
||||
case LIVELINESS_CHANGED_REMOVE_NOT_ALIVE:
|
||||
st->not_alive_count--;
|
||||
}
|
||||
} else {
|
||||
st->alive_count--;
|
||||
st->not_alive_count++;
|
||||
st->not_alive_count_change++;
|
||||
st->not_alive_count_change--;
|
||||
break;
|
||||
case LIVELINESS_CHANGED_REMOVE_ALIVE:
|
||||
st->alive_count--;
|
||||
st->alive_count_change--;
|
||||
break;
|
||||
case LIVELINESS_CHANGED_ALIVE_TO_NOT_ALIVE:
|
||||
st->alive_count--;
|
||||
st->alive_count_change--;
|
||||
st->not_alive_count++;
|
||||
st->not_alive_count_change++;
|
||||
break;
|
||||
case LIVELINESS_CHANGED_NOT_ALIVE_TO_ALIVE:
|
||||
st->not_alive_count--;
|
||||
st->not_alive_count_change--;
|
||||
st->alive_count++;
|
||||
st->alive_count_change++;
|
||||
break;
|
||||
case LIVELINESS_CHANGED_TWITCH:
|
||||
break;
|
||||
}
|
||||
st->last_publication_handle = data->handle;
|
||||
invoke = (lst->on_liveliness_changed != 0);
|
||||
|
@ -332,36 +364,37 @@ static dds_entity_t dds_create_reader_int (dds_entity_t participant_or_subscribe
|
|||
case DDS_BUILTIN_TOPIC_DCPSSUBSCRIPTION:
|
||||
internal_topic = true;
|
||||
subscriber = dds__get_builtin_subscriber (participant_or_subscriber);
|
||||
if ((ret = dds_subscriber_lock (subscriber, &sub)) != DDS_RETCODE_OK)
|
||||
return ret;
|
||||
t = dds__get_builtin_topic (subscriber, topic);
|
||||
break;
|
||||
|
||||
default: {
|
||||
dds_entity *p_or_s;
|
||||
if ((ret = dds_entity_pin (participant_or_subscriber, &p_or_s)) != DDS_RETCODE_OK)
|
||||
if ((ret = dds_entity_lock (participant_or_subscriber, DDS_KIND_DONTCARE, &p_or_s)) != DDS_RETCODE_OK)
|
||||
return ret;
|
||||
if (dds_entity_kind (p_or_s) == DDS_KIND_PARTICIPANT)
|
||||
subscriber = dds_create_subscriber (participant_or_subscriber, qos, NULL);
|
||||
else
|
||||
subscriber = participant_or_subscriber;
|
||||
dds_entity_unpin (p_or_s);
|
||||
switch (dds_entity_kind (p_or_s))
|
||||
{
|
||||
case DDS_KIND_SUBSCRIBER:
|
||||
subscriber = participant_or_subscriber;
|
||||
sub = (dds_subscriber *) p_or_s;
|
||||
break;
|
||||
case DDS_KIND_PARTICIPANT:
|
||||
subscriber = dds__create_subscriber_l ((dds_participant *) p_or_s, true, qos, NULL);
|
||||
dds_entity_unlock (p_or_s);
|
||||
if ((ret = dds_subscriber_lock (subscriber, &sub)) < 0)
|
||||
return ret;
|
||||
break;
|
||||
default:
|
||||
dds_entity_unlock (p_or_s);
|
||||
return DDS_RETCODE_ILLEGAL_OPERATION;
|
||||
}
|
||||
internal_topic = false;
|
||||
t = topic;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((ret = dds_subscriber_lock (subscriber, &sub)) != DDS_RETCODE_OK)
|
||||
{
|
||||
reader = ret;
|
||||
goto err_sub_lock;
|
||||
}
|
||||
|
||||
if (subscriber != participant_or_subscriber && !internal_topic)
|
||||
{
|
||||
/* Delete implicit subscriber if reader creation fails */
|
||||
sub->m_entity.m_flags |= DDS_ENTITY_IMPLICIT;
|
||||
}
|
||||
|
||||
if ((ret = dds_topic_lock (t, &tp)) != DDS_RETCODE_OK)
|
||||
{
|
||||
reader = ret;
|
||||
|
@ -405,7 +438,7 @@ static dds_entity_t dds_create_reader_int (dds_entity_t participant_or_subscribe
|
|||
|
||||
/* Create reader and associated read cache (if not provided by caller) */
|
||||
rd = dds_alloc (sizeof (*rd));
|
||||
reader = dds_entity_init (&rd->m_entity, &sub->m_entity, DDS_KIND_READER, rqos, listener, DDS_READER_STATUS_MASK);
|
||||
reader = dds_entity_init (&rd->m_entity, &sub->m_entity, DDS_KIND_READER, false, rqos, listener, DDS_READER_STATUS_MASK);
|
||||
rd->m_sample_rejected_status.last_reason = DDS_NOT_REJECTED;
|
||||
rd->m_topic = tp;
|
||||
rd->m_rhc = rhc ? rhc : dds_rhc_default_new (rd, tp->m_stopic);
|
||||
|
@ -431,12 +464,6 @@ static dds_entity_t dds_create_reader_int (dds_entity_t participant_or_subscribe
|
|||
|
||||
dds_topic_unlock (tp);
|
||||
dds_subscriber_unlock (sub);
|
||||
|
||||
if (internal_topic)
|
||||
{
|
||||
/* If topic is builtin, then the topic entity is local and should be deleted because the application won't. */
|
||||
dds_delete (t);
|
||||
}
|
||||
return reader;
|
||||
|
||||
err_bad_qos:
|
||||
|
@ -446,9 +473,6 @@ err_tp_lock:
|
|||
dds_subscriber_unlock (sub);
|
||||
if ((sub->m_entity.m_flags & DDS_ENTITY_IMPLICIT) != 0)
|
||||
(void) dds_delete (subscriber);
|
||||
err_sub_lock:
|
||||
if (internal_topic)
|
||||
dds_delete (t);
|
||||
return reader;
|
||||
}
|
||||
|
||||
|
|
|
@ -1110,7 +1110,7 @@ static int rhc_unregister_isreg_w_sideeffects (struct dds_rhc_default *rhc, cons
|
|||
if (inst->wrcount == 2 && inst->wr_iid_islive && inst->wr_iid != wr_iid)
|
||||
{
|
||||
TRACE (",delreg(remain)");
|
||||
lwregs_delete (&rhc->registrations, inst->iid, inst->wr_iid);
|
||||
(void) lwregs_delete (&rhc->registrations, inst->iid, inst->wr_iid);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
@ -1627,7 +1627,7 @@ static void dds_rhc_default_unregister_wr (struct dds_rhc_default * __restrict r
|
|||
}
|
||||
}
|
||||
|
||||
dds_rhc_unregister (rhc, inst, wrinfo, inst->tstamp, &post, &trig_qc);
|
||||
(void) dds_rhc_unregister (rhc, inst, wrinfo, inst->tstamp, &post, &trig_qc);
|
||||
|
||||
TRACE ("\n");
|
||||
|
||||
|
@ -2394,7 +2394,7 @@ static bool dds_rhc_default_add_readcondition (struct dds_rhc_default *rhc, dds_
|
|||
ddsrt_atomic_st32 (&cond->m_entity.m_status.m_trigger, trigger);
|
||||
dds_entity_status_signal (&cond->m_entity, DDS_DATA_AVAILABLE_STATUS);
|
||||
}
|
||||
|
||||
|
||||
TRACE ("add_readcondition(%p, %"PRIx32", %"PRIx32", %"PRIx32") => %p qminv %"PRIx32" ; rhc %"PRIu32" conds\n",
|
||||
(void *) rhc, cond->m_sample_states, cond->m_view_states,
|
||||
cond->m_instance_states, (void *) cond, cond->m_qminv, rhc->nconds);
|
||||
|
|
|
@ -256,24 +256,25 @@ size_t dds_stream_check_optimize (const dds_topic_descriptor_t * __restrict desc
|
|||
return dds_stream_check_optimize1 (desc);
|
||||
}
|
||||
|
||||
static char *dds_stream_reuse_string (dds_istream_t * __restrict is, char * __restrict str, const uint32_t bound)
|
||||
static void dds_stream_reuse_string_bound (dds_istream_t * __restrict is, char * __restrict str, const uint32_t bound)
|
||||
{
|
||||
const uint32_t length = dds_is_get4 (is);
|
||||
const void *src = is->m_buffer + is->m_index;
|
||||
if (bound)
|
||||
{
|
||||
/* FIXME: validation now rejects data containing an oversize bounded string,
|
||||
so this check is superfluous, but perhaps rejecting such a sample is the
|
||||
wrong thing to do */
|
||||
assert (str != NULL);
|
||||
memcpy (str, src, length > bound ? bound : length);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (str == NULL || strlen (str) + 1 < length)
|
||||
str = dds_realloc (str, length);
|
||||
memcpy (str, src, length);
|
||||
}
|
||||
/* FIXME: validation now rejects data containing an oversize bounded string,
|
||||
so this check is superfluous, but perhaps rejecting such a sample is the
|
||||
wrong thing to do */
|
||||
assert (str != NULL);
|
||||
memcpy (str, src, length > bound ? bound : length);
|
||||
is->m_index += length;
|
||||
}
|
||||
|
||||
static char *dds_stream_reuse_string (dds_istream_t * __restrict is, char * __restrict str)
|
||||
{
|
||||
const uint32_t length = dds_is_get4 (is);
|
||||
const void *src = is->m_buffer + is->m_index;
|
||||
if (str == NULL || strlen (str) + 1 < length)
|
||||
str = dds_realloc (str, length);
|
||||
memcpy (str, src, length);
|
||||
is->m_index += length;
|
||||
return str;
|
||||
}
|
||||
|
@ -596,7 +597,7 @@ static const uint32_t *dds_stream_read_seq (dds_istream_t * __restrict is, char
|
|||
seq->_length = (num <= seq->_maximum) ? num : seq->_maximum;
|
||||
char **ptr = (char **) seq->_buffer;
|
||||
for (uint32_t i = 0; i < seq->_length; i++)
|
||||
ptr[i] = dds_stream_reuse_string (is, ptr[i], 0);
|
||||
ptr[i] = dds_stream_reuse_string (is, ptr[i]);
|
||||
for (uint32_t i = seq->_length; i < num; i++)
|
||||
dds_stream_skip_string (is);
|
||||
return ops + 2;
|
||||
|
@ -607,7 +608,7 @@ static const uint32_t *dds_stream_read_seq (dds_istream_t * __restrict is, char
|
|||
seq->_length = (num <= seq->_maximum) ? num : seq->_maximum;
|
||||
char *ptr = (char *) seq->_buffer;
|
||||
for (uint32_t i = 0; i < seq->_length; i++)
|
||||
(void) dds_stream_reuse_string (is, ptr + i * elem_size, elem_size);
|
||||
dds_stream_reuse_string_bound (is, ptr + i * elem_size, elem_size);
|
||||
for (uint32_t i = seq->_length; i < num; i++)
|
||||
dds_stream_skip_string (is);
|
||||
return ops + 3;
|
||||
|
@ -641,14 +642,14 @@ static const uint32_t *dds_stream_read_arr (dds_istream_t * __restrict is, char
|
|||
case DDS_OP_VAL_STR: {
|
||||
char **ptr = (char **) addr;
|
||||
for (uint32_t i = 0; i < num; i++)
|
||||
ptr[i] = dds_stream_reuse_string (is, ptr[i], 0);
|
||||
ptr[i] = dds_stream_reuse_string (is, ptr[i]);
|
||||
return ops + 3;
|
||||
}
|
||||
case DDS_OP_VAL_BST: {
|
||||
char *ptr = (char *) addr;
|
||||
const uint32_t elem_size = ops[4];
|
||||
for (uint32_t i = 0; i < num; i++)
|
||||
(void) dds_stream_reuse_string (is, ptr + i * elem_size, elem_size);
|
||||
dds_stream_reuse_string_bound (is, ptr + i * elem_size, elem_size);
|
||||
return ops + 5;
|
||||
}
|
||||
case DDS_OP_VAL_SEQ: case DDS_OP_VAL_ARR: case DDS_OP_VAL_UNI: case DDS_OP_VAL_STU: {
|
||||
|
@ -685,7 +686,7 @@ static const uint32_t *dds_stream_read_uni (dds_istream_t * __restrict is, char
|
|||
case DDS_OP_VAL_2BY: *((uint16_t *) valaddr) = dds_is_get2 (is); break;
|
||||
case DDS_OP_VAL_4BY: *((uint32_t *) valaddr) = dds_is_get4 (is); break;
|
||||
case DDS_OP_VAL_8BY: *((uint64_t *) valaddr) = dds_is_get8 (is); break;
|
||||
case DDS_OP_VAL_STR: *(char **) valaddr = dds_stream_reuse_string (is, *((char **) valaddr), 0); break;
|
||||
case DDS_OP_VAL_STR: *(char **) valaddr = dds_stream_reuse_string (is, *((char **) valaddr)); break;
|
||||
case DDS_OP_VAL_BST: case DDS_OP_VAL_SEQ: case DDS_OP_VAL_ARR: case DDS_OP_VAL_UNI: case DDS_OP_VAL_STU:
|
||||
dds_stream_read (is, valaddr, jeq_op + DDS_OP_ADR_JSR (jeq_op[0]));
|
||||
break;
|
||||
|
@ -709,8 +710,8 @@ static void dds_stream_read (dds_istream_t * __restrict is, char * __restrict da
|
|||
case DDS_OP_VAL_2BY: *((uint16_t *) addr) = dds_is_get2 (is); ops += 2; break;
|
||||
case DDS_OP_VAL_4BY: *((uint32_t *) addr) = dds_is_get4 (is); ops += 2; break;
|
||||
case DDS_OP_VAL_8BY: *((uint64_t *) addr) = dds_is_get8 (is); ops += 2; break;
|
||||
case DDS_OP_VAL_STR: *((char **) addr) = dds_stream_reuse_string (is, *((char **) addr), 0); ops += 2; break;
|
||||
case DDS_OP_VAL_BST: dds_stream_reuse_string (is, (char *) addr, ops[2]); ops += 3; break;
|
||||
case DDS_OP_VAL_STR: *((char **) addr) = dds_stream_reuse_string (is, *((char **) addr)); ops += 2; break;
|
||||
case DDS_OP_VAL_BST: dds_stream_reuse_string_bound (is, (char *) addr, ops[2]); ops += 3; break;
|
||||
case DDS_OP_VAL_SEQ: ops = dds_stream_read_seq (is, addr, ops, insn); break;
|
||||
case DDS_OP_VAL_ARR: ops = dds_stream_read_arr (is, addr, ops, insn); break;
|
||||
case DDS_OP_VAL_UNI: ops = dds_stream_read_uni (is, addr, data, ops, insn); break;
|
||||
|
@ -1126,8 +1127,8 @@ void dds_stream_read_key (dds_istream_t * __restrict is, char * __restrict sampl
|
|||
case DDS_OP_VAL_2BY: *((uint16_t *) dst) = dds_is_get2 (is); break;
|
||||
case DDS_OP_VAL_4BY: *((uint32_t *) dst) = dds_is_get4 (is); break;
|
||||
case DDS_OP_VAL_8BY: *((uint64_t *) dst) = dds_is_get8 (is); break;
|
||||
case DDS_OP_VAL_STR: *((char **) dst) = dds_stream_reuse_string (is, *((char **) dst), 0); break;
|
||||
case DDS_OP_VAL_BST: dds_stream_reuse_string (is, dst, op[2]); break;
|
||||
case DDS_OP_VAL_STR: *((char **) dst) = dds_stream_reuse_string (is, *((char **) dst)); break;
|
||||
case DDS_OP_VAL_BST: dds_stream_reuse_string_bound (is, dst, op[2]); break;
|
||||
case DDS_OP_VAL_ARR:
|
||||
dds_is_get_bytes (is, dst, op[2], get_type_size (DDS_OP_SUBTYPE (*op)));
|
||||
break;
|
||||
|
@ -1728,16 +1729,16 @@ static const uint32_t *prtf_seq (char * __restrict *buf, size_t *bufsize, dds_is
|
|||
num = dds_is_get4 (is);
|
||||
if (num == 0)
|
||||
{
|
||||
prtf (buf, bufsize, "{}");
|
||||
(void) prtf (buf, bufsize, "{}");
|
||||
return skip_sequence_insns (ops, insn);
|
||||
}
|
||||
switch (subtype)
|
||||
{
|
||||
case DDS_OP_VAL_1BY: case DDS_OP_VAL_2BY: case DDS_OP_VAL_4BY: case DDS_OP_VAL_8BY:
|
||||
prtf_simple_array (buf, bufsize, is, num, subtype);
|
||||
(void) prtf_simple_array (buf, bufsize, is, num, subtype);
|
||||
return ops + 2;
|
||||
case DDS_OP_VAL_STR: case DDS_OP_VAL_BST:
|
||||
prtf_simple_array (buf, bufsize, is, num, subtype);
|
||||
(void) prtf_simple_array (buf, bufsize, is, num, subtype);
|
||||
return ops + (subtype == DDS_OP_VAL_STR ? 2 : 3);
|
||||
case DDS_OP_VAL_SEQ: case DDS_OP_VAL_ARR: case DDS_OP_VAL_UNI: case DDS_OP_VAL_STU: {
|
||||
const uint32_t jmp = DDS_OP_ADR_JMP (ops[3]);
|
||||
|
@ -1745,10 +1746,10 @@ static const uint32_t *prtf_seq (char * __restrict *buf, size_t *bufsize, dds_is
|
|||
bool cont = prtf (buf, bufsize, "{");
|
||||
for (uint32_t i = 0; cont && i < num; i++)
|
||||
{
|
||||
if (i > 0) prtf (buf, bufsize, ",");
|
||||
if (i > 0) (void) prtf (buf, bufsize, ",");
|
||||
cont = dds_stream_print_sample1 (buf, bufsize, is, jsr_ops, subtype == DDS_OP_VAL_STU);
|
||||
}
|
||||
prtf (buf, bufsize, "}");
|
||||
(void) prtf (buf, bufsize, "}");
|
||||
return ops + (jmp ? jmp : 4); /* FIXME: why would jmp be 0? */
|
||||
}
|
||||
}
|
||||
|
@ -1762,10 +1763,10 @@ static const uint32_t *prtf_arr (char * __restrict *buf, size_t *bufsize, dds_is
|
|||
switch (subtype)
|
||||
{
|
||||
case DDS_OP_VAL_1BY: case DDS_OP_VAL_2BY: case DDS_OP_VAL_4BY: case DDS_OP_VAL_8BY:
|
||||
prtf_simple_array (buf, bufsize, is, num, subtype);
|
||||
(void) prtf_simple_array (buf, bufsize, is, num, subtype);
|
||||
return ops + 3;
|
||||
case DDS_OP_VAL_STR: case DDS_OP_VAL_BST:
|
||||
prtf_simple_array (buf, bufsize, is, num, subtype);
|
||||
(void) prtf_simple_array (buf, bufsize, is, num, subtype);
|
||||
return ops + (subtype == DDS_OP_VAL_STR ? 3 : 5);
|
||||
case DDS_OP_VAL_SEQ: case DDS_OP_VAL_ARR: case DDS_OP_VAL_UNI: case DDS_OP_VAL_STU: {
|
||||
const uint32_t *jsr_ops = ops + DDS_OP_ADR_JSR (ops[3]);
|
||||
|
@ -1773,10 +1774,10 @@ static const uint32_t *prtf_arr (char * __restrict *buf, size_t *bufsize, dds_is
|
|||
bool cont = prtf (buf, bufsize, "{");
|
||||
for (uint32_t i = 0; cont && i < num; i++)
|
||||
{
|
||||
if (i > 0) prtf (buf, bufsize, ",");
|
||||
if (i > 0) (void) prtf (buf, bufsize, ",");
|
||||
cont = dds_stream_print_sample1 (buf, bufsize, is, jsr_ops, subtype == DDS_OP_VAL_STU);
|
||||
}
|
||||
prtf (buf, bufsize, "}");
|
||||
(void) prtf (buf, bufsize, "}");
|
||||
return ops + (jmp ? jmp : 5);
|
||||
}
|
||||
}
|
||||
|
@ -1787,7 +1788,7 @@ static const uint32_t *prtf_uni (char * __restrict *buf, size_t *bufsize, dds_is
|
|||
{
|
||||
const uint32_t disc = read_union_discriminant (is, DDS_OP_SUBTYPE (insn));
|
||||
uint32_t const * const jeq_op = find_union_case (ops, disc);
|
||||
prtf (buf, bufsize, "%"PRIu32":", disc);
|
||||
(void) prtf (buf, bufsize, "%"PRIu32":", disc);
|
||||
ops += DDS_OP_ADR_JMP (ops[3]);
|
||||
if (jeq_op)
|
||||
{
|
||||
|
@ -1796,10 +1797,10 @@ static const uint32_t *prtf_uni (char * __restrict *buf, size_t *bufsize, dds_is
|
|||
{
|
||||
case DDS_OP_VAL_1BY: case DDS_OP_VAL_2BY: case DDS_OP_VAL_4BY: case DDS_OP_VAL_8BY:
|
||||
case DDS_OP_VAL_STR: case DDS_OP_VAL_BST:
|
||||
prtf_simple (buf, bufsize, is, valtype);
|
||||
(void) prtf_simple (buf, bufsize, is, valtype);
|
||||
break;
|
||||
case DDS_OP_VAL_SEQ: case DDS_OP_VAL_ARR: case DDS_OP_VAL_UNI: case DDS_OP_VAL_STU:
|
||||
dds_stream_print_sample1 (buf, bufsize, is, jeq_op + DDS_OP_ADR_JSR (jeq_op[0]), valtype == DDS_OP_VAL_STU);
|
||||
(void) dds_stream_print_sample1 (buf, bufsize, is, jeq_op + DDS_OP_ADR_JSR (jeq_op[0]), valtype == DDS_OP_VAL_STU);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1812,11 +1813,11 @@ static bool dds_stream_print_sample1 (char * __restrict *buf, size_t * __restric
|
|||
bool cont = true;
|
||||
bool needs_comma = false;
|
||||
if (add_braces)
|
||||
prtf (buf, bufsize, "{");
|
||||
(void) prtf (buf, bufsize, "{");
|
||||
while (cont && (insn = *ops) != DDS_OP_RTS)
|
||||
{
|
||||
if (needs_comma)
|
||||
prtf (buf, bufsize, ",");
|
||||
(void) prtf (buf, bufsize, ",");
|
||||
needs_comma = true;
|
||||
switch (DDS_OP (insn))
|
||||
{
|
||||
|
@ -1859,13 +1860,13 @@ static bool dds_stream_print_sample1 (char * __restrict *buf, size_t * __restric
|
|||
}
|
||||
}
|
||||
if (add_braces)
|
||||
prtf (buf, bufsize, "}");
|
||||
(void) prtf (buf, bufsize, "}");
|
||||
return cont;
|
||||
}
|
||||
|
||||
size_t dds_stream_print_sample (dds_istream_t * __restrict is, const struct ddsi_sertopic_default * __restrict topic, char * __restrict buf, size_t bufsize)
|
||||
{
|
||||
dds_stream_print_sample1 (&buf, &bufsize, is, topic->type->m_ops, true);
|
||||
(void) dds_stream_print_sample1 (&buf, &bufsize, is, topic->type->m_ops, true);
|
||||
return bufsize;
|
||||
}
|
||||
|
||||
|
@ -1891,7 +1892,7 @@ size_t dds_stream_print_key (dds_istream_t * __restrict is, const struct ddsi_se
|
|||
break;
|
||||
}
|
||||
}
|
||||
prtf (&buf, &bufsize, "}");
|
||||
(void) prtf (&buf, &bufsize, "}");
|
||||
return bufsize;
|
||||
}
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ const struct dds_entity_deriver dds_entity_deriver_subscriber = {
|
|||
.validate_status = dds_subscriber_status_validate
|
||||
};
|
||||
|
||||
dds_entity_t dds__create_subscriber_l (dds_participant *participant, const dds_qos_t *qos, const dds_listener_t *listener)
|
||||
dds_entity_t dds__create_subscriber_l (dds_participant *participant, bool implicit, const dds_qos_t *qos, const dds_listener_t *listener)
|
||||
{
|
||||
/* participant entity lock must be held */
|
||||
dds_subscriber *sub;
|
||||
|
@ -64,7 +64,7 @@ dds_entity_t dds__create_subscriber_l (dds_participant *participant, const dds_q
|
|||
}
|
||||
|
||||
sub = dds_alloc (sizeof (*sub));
|
||||
subscriber = dds_entity_init (&sub->m_entity, &participant->m_entity, DDS_KIND_SUBSCRIBER, new_qos, listener, DDS_SUBSCRIBER_STATUS_MASK);
|
||||
subscriber = dds_entity_init (&sub->m_entity, &participant->m_entity, DDS_KIND_SUBSCRIBER, implicit, new_qos, listener, DDS_SUBSCRIBER_STATUS_MASK);
|
||||
sub->m_entity.m_iid = ddsi_iid_gen ();
|
||||
dds_entity_register_child (&participant->m_entity, &sub->m_entity);
|
||||
dds_entity_init_complete (&sub->m_entity);
|
||||
|
@ -78,7 +78,7 @@ dds_entity_t dds_create_subscriber (dds_entity_t participant, const dds_qos_t *q
|
|||
dds_return_t ret;
|
||||
if ((ret = dds_participant_lock (participant, &par)) != DDS_RETCODE_OK)
|
||||
return ret;
|
||||
hdl = dds__create_subscriber_l (par, qos, listener);
|
||||
hdl = dds__create_subscriber_l (par, false, qos, listener);
|
||||
dds_participant_unlock (par);
|
||||
return hdl;
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "dds/ddsi/ddsi_iid.h"
|
||||
#include "dds/ddsi/q_plist.h"
|
||||
#include "dds/ddsi/q_globals.h"
|
||||
#include "dds__serdata_builtintopic.h"
|
||||
|
||||
DECL_ENTITY_LOCK_UNLOCK (extern inline, dds_topic)
|
||||
|
||||
|
@ -135,12 +136,16 @@ static bool dds_find_topic_check_and_add_ref (dds_entity_t participant, dds_enti
|
|||
ret = false;
|
||||
else
|
||||
{
|
||||
/* FIXME: calling addref is wrong because the Cyclone library has no
|
||||
knowledge of the reference and hence simply deleting the participant
|
||||
won't make the ref count drop to 0. On the other hand, the DDS spec
|
||||
says find_topic (and a second call to create_topic) return a new
|
||||
proxy that must separately be deleted. */
|
||||
dds_entity_add_ref_locked (&tp->m_entity);
|
||||
/* Simply return the same topic, though that is different to the spirit
|
||||
of the DDS specification, which gives you a unique copy. Giving that
|
||||
unique copy means there potentially many versions of exactly the same
|
||||
topic around, and that two entities can be dealing with the same data
|
||||
even though they have different topics objects (though with the same
|
||||
name). That I find a confusing model.
|
||||
|
||||
As far as I can tell, the only benefit is the ability to set different
|
||||
listeners on the various copies of the topic. And that seems to be a
|
||||
really small benefit. */
|
||||
ret = true;
|
||||
}
|
||||
dds_topic_unlock (tp);
|
||||
|
@ -259,12 +264,7 @@ static dds_return_t create_topic_topic_arbitrary_check_sertopic (dds_entity_t pa
|
|||
ret = DDS_RETCODE_INCONSISTENT_POLICY;
|
||||
else
|
||||
{
|
||||
/* FIXME: calling addref is wrong because the Cyclone library has no
|
||||
knowledge of the reference and hence simply deleting the participant
|
||||
won't make the ref count drop to 0. On the other hand, the DDS spec
|
||||
says find_topic (and a second call to create_topic) return a new
|
||||
proxy that must separately be deleted. */
|
||||
dds_entity_add_ref_locked (&tp->m_entity);
|
||||
/* See dds_find_topic_check_and_add_ref */
|
||||
ret = DDS_RETCODE_OK;
|
||||
}
|
||||
dds_topic_unlock (tp);
|
||||
|
@ -429,7 +429,8 @@ dds_entity_t dds_create_topic_arbitrary (dds_entity_t participant, struct ddsi_s
|
|||
|
||||
/* Create topic */
|
||||
top = dds_alloc (sizeof (*top));
|
||||
hdl = dds_entity_init (&top->m_entity, &par->m_entity, DDS_KIND_TOPIC, new_qos, listener, DDS_TOPIC_STATUS_MASK);
|
||||
/* FIXME: setting "implicit" based on sertopic->ops is a hack */
|
||||
hdl = dds_entity_init (&top->m_entity, &par->m_entity, DDS_KIND_TOPIC, (sertopic->ops == &ddsi_sertopic_ops_builtintopic), new_qos, listener, DDS_TOPIC_STATUS_MASK);
|
||||
top->m_entity.m_iid = ddsi_iid_gen ();
|
||||
dds_entity_register_child (&par->m_entity, &top->m_entity);
|
||||
top->m_stopic = sertopic;
|
||||
|
|
|
@ -166,7 +166,7 @@ dds_entity_t dds_create_waitset (dds_entity_t owner)
|
|||
}
|
||||
|
||||
dds_waitset *waitset = dds_alloc (sizeof (*waitset));
|
||||
dds_entity_t hdl = dds_entity_init (&waitset->m_entity, e, DDS_KIND_WAITSET, NULL, NULL, 0);
|
||||
dds_entity_t hdl = dds_entity_init (&waitset->m_entity, e, DDS_KIND_WAITSET, false, NULL, NULL, 0);
|
||||
ddsrt_mutex_init (&waitset->wait_lock);
|
||||
ddsrt_cond_init (&waitset->wait_cond);
|
||||
waitset->m_entity.m_iid = ddsi_iid_gen ();
|
||||
|
@ -176,13 +176,13 @@ dds_entity_t dds_create_waitset (dds_entity_t owner)
|
|||
waitset->entities = NULL;
|
||||
dds_entity_init_complete (&waitset->m_entity);
|
||||
dds_entity_unlock (e);
|
||||
dds_delete_impl_pinned (&dds_global.m_entity, DIS_EXPLICIT);
|
||||
dds_entity_unpin_and_drop_ref (&dds_global.m_entity);
|
||||
return hdl;
|
||||
|
||||
err_entity_kind:
|
||||
dds_entity_unlock (e);
|
||||
err_entity_lock:
|
||||
dds_delete_impl_pinned (&dds_global.m_entity, DIS_EXPLICIT);
|
||||
dds_entity_unpin_and_drop_ref (&dds_global.m_entity);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
|
@ -209,13 +209,12 @@ static dds_return_t dds_writer_delete (dds_entity *e) ddsrt_nonnull_all;
|
|||
static dds_return_t dds_writer_delete (dds_entity *e)
|
||||
{
|
||||
dds_writer * const wr = (dds_writer *) e;
|
||||
dds_return_t ret;
|
||||
/* FIXME: not freeing WHC here because it is owned by the DDSI entity */
|
||||
thread_state_awake (lookup_thread_state (), &e->m_domain->gv);
|
||||
nn_xpack_free (wr->m_xp);
|
||||
thread_state_asleep (lookup_thread_state ());
|
||||
ret = dds_delete (wr->m_topic->m_entity.m_hdllink.hdl);
|
||||
return ret;
|
||||
dds_entity_drop_ref (&wr->m_topic->m_entity);
|
||||
return DDS_RETCODE_OK;
|
||||
}
|
||||
|
||||
static dds_return_t dds_writer_qos_set (dds_entity *e, const dds_qos_t *qos, bool enabled)
|
||||
|
@ -277,21 +276,27 @@ dds_entity_t dds_create_writer (dds_entity_t participant_or_publisher, dds_entit
|
|||
|
||||
{
|
||||
dds_entity *p_or_p;
|
||||
if ((rc = dds_entity_pin (participant_or_publisher, &p_or_p)) != DDS_RETCODE_OK)
|
||||
if ((rc = dds_entity_lock (participant_or_publisher, DDS_KIND_DONTCARE, &p_or_p)) != DDS_RETCODE_OK)
|
||||
return rc;
|
||||
if (dds_entity_kind (p_or_p) == DDS_KIND_PARTICIPANT)
|
||||
publisher = dds_create_publisher (participant_or_publisher, qos, NULL);
|
||||
else
|
||||
publisher = participant_or_publisher;
|
||||
dds_entity_unpin (p_or_p);
|
||||
switch (dds_entity_kind (p_or_p))
|
||||
{
|
||||
case DDS_KIND_PUBLISHER:
|
||||
publisher = participant_or_publisher;
|
||||
pub = (dds_publisher *) p_or_p;
|
||||
break;
|
||||
case DDS_KIND_PARTICIPANT:
|
||||
publisher = dds__create_publisher_l ((dds_participant *) p_or_p, true, qos, NULL);
|
||||
dds_entity_unlock (p_or_p);
|
||||
if ((rc = dds_publisher_lock (publisher, &pub)) < 0)
|
||||
return rc;
|
||||
break;
|
||||
default:
|
||||
dds_entity_unlock (p_or_p);
|
||||
return DDS_RETCODE_ILLEGAL_OPERATION;
|
||||
}
|
||||
}
|
||||
|
||||
if ((rc = dds_publisher_lock (publisher, &pub)) != DDS_RETCODE_OK)
|
||||
return rc;
|
||||
|
||||
ddsi_tran_conn_t conn = pub->m_entity.m_domain->gv.data_conn_uc;
|
||||
if (publisher != participant_or_publisher)
|
||||
pub->m_entity.m_flags |= DDS_ENTITY_IMPLICIT;
|
||||
|
||||
if ((rc = dds_topic_lock (topic, &tp)) != DDS_RETCODE_OK)
|
||||
goto err_tp_lock;
|
||||
|
@ -322,7 +327,7 @@ dds_entity_t dds_create_writer (dds_entity_t participant_or_publisher, dds_entit
|
|||
|
||||
/* Create writer */
|
||||
wr = dds_alloc (sizeof (*wr));
|
||||
writer = dds_entity_init (&wr->m_entity, &pub->m_entity, DDS_KIND_WRITER, wqos, listener, DDS_WRITER_STATUS_MASK);
|
||||
writer = dds_entity_init (&wr->m_entity, &pub->m_entity, DDS_KIND_WRITER, false, wqos, listener, DDS_WRITER_STATUS_MASK);
|
||||
|
||||
wr->m_topic = tp;
|
||||
dds_entity_add_ref_locked (&tp->m_entity);
|
||||
|
|
|
@ -21,12 +21,14 @@ set(ddsc_test_sources
|
|||
"config.c"
|
||||
"dispose.c"
|
||||
"domain.c"
|
||||
"domain_torture.c"
|
||||
"entity_api.c"
|
||||
"entity_hierarchy.c"
|
||||
"entity_status.c"
|
||||
"err.c"
|
||||
"instance_get_key.c"
|
||||
"listener.c"
|
||||
"liveliness.c"
|
||||
"participant.c"
|
||||
"publisher.c"
|
||||
"qos.c"
|
||||
|
@ -55,7 +57,8 @@ add_cunit_executable(cunit_ddsc ${ddsc_test_sources})
|
|||
target_include_directories(
|
||||
cunit_ddsc PRIVATE
|
||||
"$<BUILD_INTERFACE:${CMAKE_BINARY_DIR}/src/include/>"
|
||||
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../../ddsi/include/>")
|
||||
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../../ddsc/src>"
|
||||
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../../ddsi/include>")
|
||||
target_link_libraries(cunit_ddsc PRIVATE RoundTrip Space TypesArrayKey ddsc)
|
||||
|
||||
# Setup environment for config-tests
|
||||
|
|
|
@ -27,98 +27,62 @@
|
|||
#define URI_VARIABLE DDS_PROJECT_NAME_NOSPACE_CAPS"_URI"
|
||||
#define MAX_PARTICIPANTS_VARIABLE "MAX_PARTICIPANTS"
|
||||
|
||||
static void config__check_env(
|
||||
const char * env_variable,
|
||||
const char * expected_value)
|
||||
static void config__check_env (const char *env_variable, const char *expected_value)
|
||||
{
|
||||
char * env_uri = NULL;
|
||||
ddsrt_getenv(env_variable, &env_uri);
|
||||
#if 0
|
||||
const char * const env_not_set = "Environment variable '%s' isn't set. This needs to be set to '%s' for this test to run.";
|
||||
const char * const env_not_as_expected = "Environment variable '%s' has an unexpected value: '%s' (expected: '%s')";
|
||||
#endif
|
||||
|
||||
char *env_uri = NULL;
|
||||
ddsrt_getenv (env_variable, &env_uri);
|
||||
#ifdef FORCE_ENV
|
||||
{
|
||||
bool env_ok;
|
||||
|
||||
if (env_uri == NULL)
|
||||
env_ok = false;
|
||||
else if (strncmp (env_uri, expected_value, strlen (expected_value)) != 0)
|
||||
env_ok = false;
|
||||
else
|
||||
env_ok = true;
|
||||
|
||||
if (!env_ok)
|
||||
{
|
||||
bool env_ok;
|
||||
|
||||
if ( env_uri == NULL ) {
|
||||
env_ok = false;
|
||||
} else if ( strncmp(env_uri, expected_value, strlen(expected_value)) != 0 ) {
|
||||
env_ok = false;
|
||||
} else {
|
||||
env_ok = true;
|
||||
}
|
||||
|
||||
if ( !env_ok ) {
|
||||
dds_return_t r;
|
||||
|
||||
r = ddsrt_setenv(env_variable, expected_value);
|
||||
CU_ASSERT_EQUAL_FATAL(r, DDS_RETCODE_OK);
|
||||
}
|
||||
dds_return_t r = ddsrt_setenv (env_variable, expected_value);
|
||||
CU_ASSERT_EQUAL_FATAL (r, DDS_RETCODE_OK);
|
||||
}
|
||||
}
|
||||
#else
|
||||
CU_ASSERT_PTR_NOT_NULL_FATAL(env_uri);
|
||||
CU_ASSERT_STRING_EQUAL_FATAL(env_uri, expected_value);
|
||||
CU_ASSERT_PTR_NOT_NULL_FATAL (env_uri);
|
||||
CU_ASSERT_STRING_EQUAL_FATAL (env_uri, expected_value);
|
||||
#endif /* FORCE_ENV */
|
||||
|
||||
}
|
||||
|
||||
CU_Test(ddsc_config, simple_udp, .init = ddsrt_init, .fini = ddsrt_fini) {
|
||||
|
||||
dds_entity_t participant;
|
||||
|
||||
config__check_env(URI_VARIABLE, CONFIG_ENV_SIMPLE_UDP);
|
||||
config__check_env(MAX_PARTICIPANTS_VARIABLE, CONFIG_ENV_MAX_PARTICIPANTS);
|
||||
|
||||
participant = dds_create_participant(DDS_DOMAIN_DEFAULT, NULL, NULL);
|
||||
|
||||
CU_ASSERT_FATAL(participant> 0);
|
||||
|
||||
dds_delete(participant);
|
||||
CU_Test (ddsc_config, simple_udp, .init = ddsrt_init, .fini = ddsrt_fini)
|
||||
{
|
||||
dds_entity_t participant;
|
||||
config__check_env (URI_VARIABLE, CONFIG_ENV_SIMPLE_UDP);
|
||||
config__check_env (MAX_PARTICIPANTS_VARIABLE, CONFIG_ENV_MAX_PARTICIPANTS);
|
||||
participant = dds_create_participant (DDS_DOMAIN_DEFAULT, NULL, NULL);
|
||||
CU_ASSERT_FATAL (participant> 0);
|
||||
dds_delete (participant);
|
||||
}
|
||||
|
||||
CU_Test(ddsc_config, user_config, .init = ddsrt_init, .fini = ddsrt_fini) {
|
||||
CU_Test (ddsc_config, user_config, .init = ddsrt_init, .fini = ddsrt_fini)
|
||||
{
|
||||
dds_entity_t domain;
|
||||
domain = dds_create_domain (1,
|
||||
"<"DDS_PROJECT_NAME"><Domain><Id>any</Id></Domain>"
|
||||
"<DDSI2E><Internal><MaxParticipants>2</MaxParticipants></Internal></DDSI2E>"
|
||||
"</"DDS_PROJECT_NAME">");
|
||||
CU_ASSERT_FATAL (domain > 0);
|
||||
|
||||
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_create_participant (1, NULL, NULL);
|
||||
CU_ASSERT_FATAL(participant_1 > 0);
|
||||
|
||||
dds_entity_t participant_1;
|
||||
dds_entity_t participant_2;
|
||||
dds_entity_t participant_3;
|
||||
dds_entity_t participant_2 = dds_create_participant (1, NULL, NULL);
|
||||
CU_ASSERT_FATAL(participant_2 > 0);
|
||||
|
||||
participant_1 = dds_create_participant(1, NULL, NULL);
|
||||
dds_entity_t participant_3 = dds_create_participant (1, NULL, NULL);
|
||||
CU_ASSERT(participant_3 < 0);
|
||||
|
||||
CU_ASSERT_FATAL(participant_1 > 0);
|
||||
|
||||
participant_2 = dds_create_participant(1, NULL, NULL);
|
||||
|
||||
CU_ASSERT_FATAL(participant_2 > 0);
|
||||
|
||||
participant_3 = dds_create_participant(1, NULL, NULL);
|
||||
|
||||
CU_ASSERT(participant_3 <= 0);
|
||||
|
||||
dds_delete(participant_3);
|
||||
dds_delete(participant_2);
|
||||
dds_delete(participant_1);
|
||||
}
|
||||
|
||||
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);
|
||||
dds_delete (domain);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -823,4 +787,5 @@ CU_Test(ddsc_config, security_qos_invalid, .init = ddsrt_init, .fini = ddsrt_fin
|
|||
#endif
|
||||
dds_set_log_sink(NULL, NULL);
|
||||
dds_set_trace_sink(NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<?xml-model href="https://raw.githubusercontent.com/eclipse-cyclonedds/cyclonedds/master/etc/cyclonedds.xsd"
|
||||
schematypens="http://www.w3.org/2001/XMLSchema" ?>
|
||||
<!--
|
||||
Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
|
||||
|
||||
|
@ -10,10 +12,10 @@
|
|||
|
||||
SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
|
||||
-->
|
||||
<CycloneDDS>
|
||||
<CycloneDDS xmlns="https://cdds.io/config">
|
||||
<!-- Simple config-file for testing whether a config-file can be picked up
|
||||
correctly. -->
|
||||
<Domain id="3">
|
||||
<Domain Id="3">
|
||||
<General>
|
||||
<NetworkInterfaceAddress>127.0.0.1</NetworkInterfaceAddress>
|
||||
<AllowMulticast>true</AllowMulticast>
|
||||
|
@ -28,8 +30,8 @@
|
|||
</Tracing>
|
||||
<Internal>
|
||||
<MaxParticipants>${MAX_PARTICIPANTS}</MaxParticipants>
|
||||
<HeartbeatInterval max="10 s"> 100 ms </HeartbeatInterval>
|
||||
<RediscoveryBlacklistDuration></RediscoveryBlacklistDuration>
|
||||
<HeartbeatInterval>100 ms</HeartbeatInterval>
|
||||
<RediscoveryBlacklistDuration>10s</RediscoveryBlacklistDuration>
|
||||
</Internal>
|
||||
</Domain>
|
||||
</CycloneDDS>
|
||||
|
|
|
@ -140,3 +140,150 @@ CU_Test(ddsc_domain, delete_cyclonedds)
|
|||
rc = dds_get_domainid (pp[0], &did);
|
||||
CU_ASSERT_FATAL (rc == DDS_RETCODE_PRECONDITION_NOT_MET);
|
||||
}
|
||||
|
||||
CU_Test(ddsc_domain_create, valid)
|
||||
{
|
||||
dds_return_t ret;
|
||||
dds_domainid_t did;
|
||||
dds_entity_t domain;
|
||||
|
||||
domain = dds_create_domain(1, "<"DDS_PROJECT_NAME"><Domain><Id>1</Id></Domain></"DDS_PROJECT_NAME">");
|
||||
CU_ASSERT_FATAL(domain > 0);
|
||||
|
||||
ret = dds_get_domainid (domain, &did);
|
||||
CU_ASSERT_FATAL(ret == DDS_RETCODE_OK);
|
||||
CU_ASSERT_FATAL(did == 1);
|
||||
|
||||
ret = dds_delete(domain);
|
||||
CU_ASSERT_FATAL(ret == DDS_RETCODE_OK);
|
||||
ret = dds_delete(domain);
|
||||
CU_ASSERT_FATAL(ret != DDS_RETCODE_OK);
|
||||
}
|
||||
|
||||
CU_Test(ddsc_domain_create, mismatch)
|
||||
{
|
||||
dds_return_t ret;
|
||||
dds_domainid_t did;
|
||||
dds_entity_t domain;
|
||||
|
||||
/* The config should have been ignored. */
|
||||
domain = dds_create_domain(2, "<"DDS_PROJECT_NAME"><Domain><Id>3</Id></Domain></"DDS_PROJECT_NAME">");
|
||||
CU_ASSERT_FATAL(domain > 0);
|
||||
|
||||
ret = dds_get_domainid (domain, &did);
|
||||
CU_ASSERT_FATAL(ret == DDS_RETCODE_OK);
|
||||
CU_ASSERT_FATAL(did == 2);
|
||||
|
||||
ret = dds_delete(domain);
|
||||
CU_ASSERT_FATAL(ret == DDS_RETCODE_OK);
|
||||
}
|
||||
|
||||
CU_Test(ddsc_domain_create, empty)
|
||||
{
|
||||
dds_return_t ret;
|
||||
dds_domainid_t did;
|
||||
dds_entity_t domain;
|
||||
|
||||
/* This should create a domain with default settings. */
|
||||
domain = dds_create_domain(3, "");
|
||||
CU_ASSERT_FATAL(domain > 0);
|
||||
|
||||
ret = dds_get_domainid (domain, &did);
|
||||
CU_ASSERT_FATAL(ret == DDS_RETCODE_OK);
|
||||
CU_ASSERT_FATAL(did == 3);
|
||||
|
||||
ret = dds_delete(domain);
|
||||
CU_ASSERT_FATAL(ret == DDS_RETCODE_OK);
|
||||
}
|
||||
|
||||
CU_Test(ddsc_domain_create, null)
|
||||
{
|
||||
dds_return_t ret;
|
||||
dds_domainid_t did;
|
||||
dds_entity_t domain;
|
||||
|
||||
/* This should start create a domain with default settings. */
|
||||
domain = dds_create_domain(5, NULL);
|
||||
CU_ASSERT_FATAL(domain > 0);
|
||||
|
||||
ret = dds_get_domainid (domain, &did);
|
||||
CU_ASSERT_FATAL(ret == DDS_RETCODE_OK);
|
||||
CU_ASSERT_FATAL(did == 5);
|
||||
|
||||
ret = dds_delete(domain);
|
||||
CU_ASSERT_FATAL(ret == DDS_RETCODE_OK);
|
||||
}
|
||||
|
||||
CU_Test(ddsc_domain_create, after_domain)
|
||||
{
|
||||
dds_entity_t domain1;
|
||||
dds_entity_t domain2;
|
||||
|
||||
domain1 = dds_create_domain(4, "<"DDS_PROJECT_NAME"><Domain><Id>any</Id></Domain></"DDS_PROJECT_NAME">");
|
||||
CU_ASSERT_FATAL(domain1 > 0);
|
||||
|
||||
domain2 = dds_create_domain(4, "<"DDS_PROJECT_NAME"><Domain><Id>any</Id></Domain></"DDS_PROJECT_NAME">");
|
||||
CU_ASSERT_FATAL(domain2 == DDS_RETCODE_PRECONDITION_NOT_MET);
|
||||
|
||||
dds_delete(domain1);
|
||||
}
|
||||
|
||||
CU_Test(ddsc_domain_create, after_participant)
|
||||
{
|
||||
dds_entity_t domain;
|
||||
dds_entity_t participant;
|
||||
|
||||
participant = dds_create_participant (5, NULL, NULL);
|
||||
CU_ASSERT_FATAL(participant > 0);
|
||||
|
||||
domain = dds_create_domain(5, "<"DDS_PROJECT_NAME"><Domain><Id>any</Id></Domain></"DDS_PROJECT_NAME">");
|
||||
CU_ASSERT_FATAL(domain == DDS_RETCODE_PRECONDITION_NOT_MET);
|
||||
|
||||
dds_delete(participant);
|
||||
}
|
||||
|
||||
CU_Test(ddsc_domain_create, diff)
|
||||
{
|
||||
dds_return_t ret;
|
||||
dds_domainid_t did;
|
||||
dds_entity_t domain1;
|
||||
dds_entity_t domain2;
|
||||
|
||||
domain1 = dds_create_domain(1, "<"DDS_PROJECT_NAME"><Domain><Id>any</Id></Domain></"DDS_PROJECT_NAME">");
|
||||
CU_ASSERT_FATAL(domain1 > 0);
|
||||
|
||||
domain2 = dds_create_domain(2, "<"DDS_PROJECT_NAME"><Domain><Id>any</Id></Domain></"DDS_PROJECT_NAME">");
|
||||
CU_ASSERT_FATAL(domain2 > 0);
|
||||
|
||||
ret = dds_get_domainid (domain1, &did);
|
||||
CU_ASSERT_FATAL(ret == DDS_RETCODE_OK);
|
||||
CU_ASSERT_FATAL(did == 1);
|
||||
|
||||
ret = dds_get_domainid (domain2, &did);
|
||||
CU_ASSERT_FATAL(ret == DDS_RETCODE_OK);
|
||||
CU_ASSERT_FATAL(did == 2);
|
||||
|
||||
ret = dds_delete(domain1);
|
||||
CU_ASSERT_FATAL(ret == DDS_RETCODE_OK);
|
||||
ret = dds_delete(domain2);
|
||||
CU_ASSERT_FATAL(ret == DDS_RETCODE_OK);
|
||||
|
||||
ret = dds_delete(domain1);
|
||||
CU_ASSERT_FATAL(ret != DDS_RETCODE_OK);
|
||||
ret = dds_delete(domain2);
|
||||
CU_ASSERT_FATAL(ret != DDS_RETCODE_OK);
|
||||
}
|
||||
|
||||
CU_Test(ddsc_domain_create, domain_default)
|
||||
{
|
||||
dds_entity_t domain;
|
||||
domain = dds_create_domain(DDS_DOMAIN_DEFAULT, "<"DDS_PROJECT_NAME"><Domain><Id>any</Id></Domain></"DDS_PROJECT_NAME">");
|
||||
CU_ASSERT_FATAL(domain == DDS_RETCODE_BAD_PARAMETER);
|
||||
}
|
||||
|
||||
CU_Test(ddsc_domain_create, invalid_xml)
|
||||
{
|
||||
dds_entity_t domain;
|
||||
domain = dds_create_domain(1, "<CycloneDDS incorrect XML");
|
||||
CU_ASSERT_FATAL(domain == DDS_RETCODE_ERROR);
|
||||
}
|
||||
|
|
118
src/core/ddsc/tests/domain_torture.c
Normal file
118
src/core/ddsc/tests/domain_torture.c
Normal file
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* Copyright(c) 2019 ADLINK Technology Limited and others
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
|
||||
* v. 1.0 which is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "dds/dds.h"
|
||||
#include "CUnit/Theory.h"
|
||||
#include "RoundTrip.h"
|
||||
|
||||
#include "dds/ddsrt/threads.h"
|
||||
#include "dds/ddsrt/atomics.h"
|
||||
#include "dds/ddsrt/time.h"
|
||||
|
||||
|
||||
#define N_THREADS (10)
|
||||
|
||||
static const dds_duration_t TEST_DURATION = DDS_SECS(3);
|
||||
|
||||
static ddsrt_atomic_uint32_t terminate;
|
||||
|
||||
|
||||
static uint32_t create_participants_thread (void *varg)
|
||||
{
|
||||
(void) varg;
|
||||
while (!ddsrt_atomic_ld32 (&terminate))
|
||||
{
|
||||
dds_entity_t par = dds_create_participant (DDS_DOMAIN_DEFAULT, NULL, NULL);
|
||||
if (par < 0)
|
||||
{
|
||||
fprintf (stderr, "dds_create_participant failed: %s\n", dds_strretcode (par));
|
||||
ddsrt_atomic_st32 (&terminate, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
dds_return_t ret = dds_delete(par);
|
||||
if (ret != DDS_RETCODE_OK)
|
||||
{
|
||||
fprintf (stderr, "dds_delete failed: %s\n", dds_strretcode (ret));
|
||||
ddsrt_atomic_st32 (&terminate, 1);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void participant_creation_torture()
|
||||
{
|
||||
dds_return_t rc;
|
||||
ddsrt_thread_t tids[N_THREADS];
|
||||
ddsrt_threadattr_t tattr;
|
||||
ddsrt_threadattr_init (&tattr);
|
||||
|
||||
/* Start threads. */
|
||||
for (size_t i = 0; i < sizeof(tids) / sizeof(*tids); i++)
|
||||
{
|
||||
rc = ddsrt_thread_create (&tids[i], "domain_torture_explicit", &tattr, create_participants_thread, 0);
|
||||
CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
|
||||
}
|
||||
|
||||
/* Let the threads do the torturing for a while. */
|
||||
dds_sleepfor(TEST_DURATION);
|
||||
|
||||
/* Stop and check threads results. */
|
||||
ddsrt_atomic_st32 (&terminate, 1);
|
||||
for (size_t i = 0; i < sizeof (tids) / sizeof (tids[0]); i++)
|
||||
{
|
||||
uint32_t retval;
|
||||
rc = ddsrt_thread_join (tids[i], &retval);
|
||||
CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
|
||||
CU_ASSERT (retval == 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* There are some issues when completely init/deinit the
|
||||
* library in a torturing way. We really just want to
|
||||
* check the domain creation/deletion. So, disable this
|
||||
* test for now.
|
||||
*/
|
||||
CU_Test (ddsc_domain, torture_implicit, .disabled=true)
|
||||
{
|
||||
/* No explicit domain creation, just start creating and
|
||||
* deleting participants (that'll create and delete the
|
||||
* domain implicitly) in a torturing manner. */
|
||||
participant_creation_torture();
|
||||
}
|
||||
|
||||
|
||||
CU_Test (ddsc_domain, torture_explicit)
|
||||
{
|
||||
dds_return_t rc;
|
||||
dds_entity_t domain;
|
||||
|
||||
/* Create domain explicitly. */
|
||||
domain = dds_create_domain(1, "");
|
||||
CU_ASSERT_FATAL (domain > 0);
|
||||
|
||||
/* Start creating and deleting participants on the
|
||||
* explicit domain in a torturing manner. */
|
||||
participant_creation_torture();
|
||||
|
||||
/* Delete domain. */
|
||||
rc = dds_delete(domain);
|
||||
CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
|
||||
rc = dds_delete(domain);
|
||||
CU_ASSERT_FATAL (rc != DDS_RETCODE_OK);
|
||||
}
|
|
@ -192,6 +192,10 @@ CU_Test(ddsc_entity_delete, recursive_with_deleted_topic)
|
|||
ret = dds_delete(g_topic);
|
||||
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
|
||||
|
||||
/* Second call to delete a topic must fail */
|
||||
ret = dds_delete(g_topic);
|
||||
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_ALREADY_DELETED);
|
||||
|
||||
/* Third, deleting the participant should delete all children of which
|
||||
* the writer with the last topic reference is one. */
|
||||
ret = dds_delete(g_participant);
|
||||
|
@ -988,6 +992,70 @@ CU_Test(ddsc_entity_get_parent, implicit_subscriber)
|
|||
}
|
||||
/*************************************************************************************************/
|
||||
|
||||
/*************************************************************************************************/
|
||||
CU_Test(ddsc_entity_implicit, delete_publisher)
|
||||
{
|
||||
dds_entity_t participant;
|
||||
dds_entity_t writer;
|
||||
dds_entity_t parent;
|
||||
dds_entity_t topic;
|
||||
dds_return_t ret;
|
||||
char name[100];
|
||||
|
||||
participant = dds_create_participant(DDS_DOMAIN_DEFAULT, NULL, NULL);
|
||||
CU_ASSERT_FATAL(participant > 0);
|
||||
|
||||
topic = dds_create_topic(participant, &RoundTripModule_DataType_desc, create_topic_name("ddsc_entity_implicit_delete_publisher", name, 100), NULL, NULL);
|
||||
CU_ASSERT_FATAL(topic > 0);
|
||||
|
||||
writer = dds_create_writer(participant, topic, NULL, NULL);
|
||||
CU_ASSERT_FATAL(writer > 0);
|
||||
|
||||
parent = dds_get_parent(writer);
|
||||
CU_ASSERT_FATAL(parent > 0);
|
||||
|
||||
ret = dds_delete(parent);
|
||||
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
|
||||
|
||||
ret = dds_delete(writer);
|
||||
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER);
|
||||
|
||||
dds_delete(participant);
|
||||
}
|
||||
/*************************************************************************************************/
|
||||
|
||||
/*************************************************************************************************/
|
||||
CU_Test(ddsc_entity_implicit, delete_subscriber)
|
||||
{
|
||||
dds_entity_t participant;
|
||||
dds_entity_t reader;
|
||||
dds_entity_t parent;
|
||||
dds_entity_t topic;
|
||||
dds_return_t ret;
|
||||
char name[100];
|
||||
|
||||
participant = dds_create_participant(DDS_DOMAIN_DEFAULT, NULL, NULL);
|
||||
CU_ASSERT_FATAL(participant > 0);
|
||||
|
||||
topic = dds_create_topic(participant, &RoundTripModule_DataType_desc, create_topic_name("ddsc_entity_implicit_delete_subscriber", name, 100), NULL, NULL);
|
||||
CU_ASSERT_FATAL(topic > 0);
|
||||
|
||||
reader = dds_create_reader(participant, topic, NULL, NULL);
|
||||
CU_ASSERT_FATAL(reader > 0);
|
||||
|
||||
parent = dds_get_parent(reader);
|
||||
CU_ASSERT_FATAL(parent > 0);
|
||||
|
||||
ret = dds_delete(parent);
|
||||
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
|
||||
|
||||
ret = dds_delete(reader);
|
||||
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER);
|
||||
|
||||
dds_delete(participant);
|
||||
}
|
||||
/*************************************************************************************************/
|
||||
|
||||
/*************************************************************************************************/
|
||||
|
||||
#endif
|
||||
|
|
|
@ -360,9 +360,9 @@ CU_Test(ddsc_entity, liveliness_changed, .init=init_entity_status, .fini=fini_en
|
|||
ret = dds_get_liveliness_changed_status (rea, &liveliness_changed);
|
||||
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
|
||||
CU_ASSERT_EQUAL_FATAL(liveliness_changed.alive_count, 0);
|
||||
CU_ASSERT_EQUAL_FATAL(liveliness_changed.alive_count_change, 0);
|
||||
CU_ASSERT_EQUAL_FATAL(liveliness_changed.not_alive_count, 1);
|
||||
CU_ASSERT_EQUAL_FATAL(liveliness_changed.not_alive_count_change,1);
|
||||
CU_ASSERT_EQUAL_FATAL(liveliness_changed.alive_count_change, -1);
|
||||
CU_ASSERT_EQUAL_FATAL(liveliness_changed.not_alive_count, 0);
|
||||
CU_ASSERT_EQUAL_FATAL(liveliness_changed.not_alive_count_change,0);
|
||||
CU_ASSERT_EQUAL_FATAL(liveliness_changed.last_publication_handle, writer_i_hdl);
|
||||
|
||||
/* Second call should reset the changed count. */
|
||||
|
@ -370,7 +370,7 @@ CU_Test(ddsc_entity, liveliness_changed, .init=init_entity_status, .fini=fini_en
|
|||
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
|
||||
CU_ASSERT_EQUAL_FATAL(liveliness_changed.alive_count, 0);
|
||||
CU_ASSERT_EQUAL_FATAL(liveliness_changed.alive_count_change, 0);
|
||||
CU_ASSERT_EQUAL_FATAL(liveliness_changed.not_alive_count, 1);
|
||||
CU_ASSERT_EQUAL_FATAL(liveliness_changed.not_alive_count, 0);
|
||||
CU_ASSERT_EQUAL_FATAL(liveliness_changed.not_alive_count_change,0);
|
||||
CU_ASSERT_EQUAL_FATAL(liveliness_changed.last_publication_handle, writer_i_hdl);
|
||||
}
|
||||
|
|
|
@ -1196,9 +1196,9 @@ CU_Test(ddsc_listener, liveliness_changed, .init=init_triggering_test, .fini=fin
|
|||
CU_ASSERT_EQUAL_FATAL(triggered & DDS_LIVELINESS_CHANGED_STATUS, DDS_LIVELINESS_CHANGED_STATUS);
|
||||
CU_ASSERT_EQUAL_FATAL(cb_reader, g_reader);
|
||||
CU_ASSERT_EQUAL_FATAL(cb_liveliness_changed_status.alive_count, 0);
|
||||
CU_ASSERT_EQUAL_FATAL(cb_liveliness_changed_status.alive_count_change, 0);
|
||||
CU_ASSERT_EQUAL_FATAL(cb_liveliness_changed_status.not_alive_count, 1);
|
||||
CU_ASSERT_EQUAL_FATAL(cb_liveliness_changed_status.not_alive_count_change, 1);
|
||||
CU_ASSERT_EQUAL_FATAL(cb_liveliness_changed_status.alive_count_change, -1);
|
||||
CU_ASSERT_EQUAL_FATAL(cb_liveliness_changed_status.not_alive_count, 0);
|
||||
CU_ASSERT_EQUAL_FATAL(cb_liveliness_changed_status.not_alive_count_change, 0);
|
||||
CU_ASSERT_EQUAL_FATAL(cb_liveliness_changed_status.last_publication_handle, writer_hdl);
|
||||
|
||||
/* The listener should have reset the count_change. */
|
||||
|
@ -1206,7 +1206,7 @@ CU_Test(ddsc_listener, liveliness_changed, .init=init_triggering_test, .fini=fin
|
|||
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
|
||||
CU_ASSERT_EQUAL_FATAL(liveliness_changed.alive_count, 0);
|
||||
CU_ASSERT_EQUAL_FATAL(liveliness_changed.alive_count_change, 0);
|
||||
CU_ASSERT_EQUAL_FATAL(liveliness_changed.not_alive_count, 1);
|
||||
CU_ASSERT_EQUAL_FATAL(liveliness_changed.not_alive_count, 0);
|
||||
CU_ASSERT_EQUAL_FATAL(liveliness_changed.not_alive_count_change, 0);
|
||||
CU_ASSERT_EQUAL_FATAL(liveliness_changed.last_publication_handle, writer_hdl);
|
||||
}
|
||||
|
|
815
src/core/ddsc/tests/liveliness.c
Normal file
815
src/core/ddsc/tests/liveliness.c
Normal file
|
@ -0,0 +1,815 @@
|
|||
/*
|
||||
* 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 "Space.h"
|
||||
#include "config_env.h"
|
||||
|
||||
#include "dds/version.h"
|
||||
#include "dds__entity.h"
|
||||
#include "dds/ddsi/q_entity.h"
|
||||
#include "dds/ddsrt/cdtors.h"
|
||||
#include "dds/ddsrt/misc.h"
|
||||
#include "dds/ddsrt/process.h"
|
||||
#include "dds/ddsrt/threads.h"
|
||||
#include "dds/ddsrt/environ.h"
|
||||
#include "dds/ddsrt/atomics.h"
|
||||
#include "dds/ddsrt/time.h"
|
||||
|
||||
#define DDS_DOMAINID_PUB 0
|
||||
#define DDS_DOMAINID_SUB 1
|
||||
#define DDS_CONFIG_NO_PORT_GAIN "${CYCLONEDDS_URI}${CYCLONEDDS_URI:+,}<Discovery><ExternalDomainId>0</ExternalDomainId></Discovery>"
|
||||
#define DDS_CONFIG_NO_PORT_GAIN_LOG "${CYCLONEDDS_URI}${CYCLONEDDS_URI:+,}<Tracing><OutputFile>cyclonedds_liveliness_tests.${CYCLONEDDS_DOMAIN_ID}.${CYCLONEDDS_PID}.log</OutputFile><Verbosity>finest</Verbosity></Tracing><Discovery><ExternalDomainId>0</ExternalDomainId></Discovery>"
|
||||
|
||||
uint32_t g_topic_nr = 0;
|
||||
static dds_entity_t g_pub_domain = 0;
|
||||
static dds_entity_t g_pub_participant = 0;
|
||||
static dds_entity_t g_pub_publisher = 0;
|
||||
|
||||
static dds_entity_t g_sub_domain = 0;
|
||||
static dds_entity_t g_sub_participant = 0;
|
||||
static dds_entity_t g_sub_subscriber = 0;
|
||||
|
||||
static char *create_topic_name(const char *prefix, uint32_t nr, char *name, size_t size)
|
||||
{
|
||||
/* Get unique g_topic name. */
|
||||
ddsrt_pid_t pid = ddsrt_getpid();
|
||||
ddsrt_tid_t tid = ddsrt_gettid();
|
||||
(void)snprintf(name, size, "%s%d_pid%" PRIdPID "_tid%" PRIdTID "", prefix, nr, pid, tid);
|
||||
return name;
|
||||
}
|
||||
|
||||
static void liveliness_init(void)
|
||||
{
|
||||
/* Domains for pub and sub use a different domain id, but the portgain setting
|
||||
* in configuration is 0, so that both domains will map to the same port number.
|
||||
* This allows to create two domains in a single test process. */
|
||||
char *conf_pub = ddsrt_expand_envvars(DDS_CONFIG_NO_PORT_GAIN, DDS_DOMAINID_PUB);
|
||||
char *conf_sub = ddsrt_expand_envvars(DDS_CONFIG_NO_PORT_GAIN, DDS_DOMAINID_SUB);
|
||||
g_pub_domain = dds_create_domain(DDS_DOMAINID_PUB, conf_pub);
|
||||
g_sub_domain = dds_create_domain(DDS_DOMAINID_SUB, conf_sub);
|
||||
dds_free(conf_pub);
|
||||
dds_free(conf_sub);
|
||||
|
||||
g_pub_participant = dds_create_participant(DDS_DOMAINID_PUB, NULL, NULL);
|
||||
CU_ASSERT_FATAL(g_pub_participant > 0);
|
||||
g_sub_participant = dds_create_participant(DDS_DOMAINID_SUB, NULL, NULL);
|
||||
CU_ASSERT_FATAL(g_sub_participant > 0);
|
||||
|
||||
g_pub_publisher = dds_create_publisher(g_pub_participant, NULL, NULL);
|
||||
CU_ASSERT_FATAL(g_pub_publisher > 0);
|
||||
g_sub_subscriber = dds_create_subscriber(g_sub_participant, NULL, NULL);
|
||||
CU_ASSERT_FATAL(g_sub_subscriber > 0);
|
||||
}
|
||||
|
||||
static void liveliness_fini(void)
|
||||
{
|
||||
dds_delete(g_sub_subscriber);
|
||||
dds_delete(g_pub_publisher);
|
||||
dds_delete(g_sub_participant);
|
||||
dds_delete(g_pub_participant);
|
||||
dds_delete(g_sub_domain);
|
||||
dds_delete(g_pub_domain);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current PMD sequence number for the participant. This
|
||||
* can be used to count the number of PMD messages that is sent by
|
||||
* the participant.
|
||||
*/
|
||||
static seqno_t get_pmd_seqno(dds_entity_t participant)
|
||||
{
|
||||
seqno_t seqno;
|
||||
struct dds_entity *pp_entity;
|
||||
struct participant *pp;
|
||||
struct writer *wr;
|
||||
CU_ASSERT_EQUAL_FATAL(dds_entity_pin(participant, &pp_entity), 0);
|
||||
thread_state_awake(lookup_thread_state(), &pp_entity->m_domain->gv);
|
||||
pp = ephash_lookup_participant_guid(pp_entity->m_domain->gv.guid_hash, &pp_entity->m_guid);
|
||||
wr = get_builtin_writer(pp, NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER);
|
||||
CU_ASSERT_FATAL(wr != NULL);
|
||||
assert(wr != NULL); /* for Clang's static analyzer */
|
||||
seqno = wr->seq;
|
||||
thread_state_asleep(lookup_thread_state());
|
||||
dds_entity_unpin(pp_entity);
|
||||
return seqno;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current PMD interval for the participant
|
||||
*/
|
||||
static dds_duration_t get_pmd_interval(dds_entity_t participant)
|
||||
{
|
||||
dds_duration_t intv;
|
||||
struct dds_entity *pp_entity;
|
||||
struct participant *pp;
|
||||
CU_ASSERT_EQUAL_FATAL(dds_entity_pin(participant, &pp_entity), 0);
|
||||
thread_state_awake(lookup_thread_state(), &pp_entity->m_domain->gv);
|
||||
pp = ephash_lookup_participant_guid(pp_entity->m_domain->gv.guid_hash, &pp_entity->m_guid);
|
||||
intv = pp_get_pmd_interval(pp);
|
||||
thread_state_asleep(lookup_thread_state());
|
||||
dds_entity_unpin(pp_entity);
|
||||
return intv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current lease duration for the participant
|
||||
*/
|
||||
static dds_duration_t get_ldur_config(dds_entity_t participant)
|
||||
{
|
||||
struct dds_entity *pp_entity;
|
||||
dds_duration_t ldur;
|
||||
CU_ASSERT_EQUAL_FATAL(dds_entity_pin(participant, &pp_entity), 0);
|
||||
ldur = (dds_duration_t)pp_entity->m_domain->gv.config.lease_duration;
|
||||
dds_entity_unpin(pp_entity);
|
||||
return ldur;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that the correct number of PMD messages is sent for
|
||||
* the various liveliness kinds.
|
||||
*/
|
||||
#define A DDS_LIVELINESS_AUTOMATIC
|
||||
#define MP DDS_LIVELINESS_MANUAL_BY_PARTICIPANT
|
||||
#define MT DDS_LIVELINESS_MANUAL_BY_TOPIC
|
||||
CU_TheoryDataPoints(ddsc_liveliness, pmd_count) = {
|
||||
CU_DataPoints(dds_liveliness_kind_t, A, A, MP, MT), /* liveliness kind */
|
||||
CU_DataPoints(uint32_t, 200, 500, 100, 100), /* lease duration */
|
||||
CU_DataPoints(double, 10, 5, 5, 5), /* delay (n times lease duration) */
|
||||
};
|
||||
#undef MT
|
||||
#undef MP
|
||||
#undef A
|
||||
CU_Theory((dds_liveliness_kind_t kind, uint32_t ldur, double mult), ddsc_liveliness, pmd_count, .init = liveliness_init, .fini = liveliness_fini, .timeout = 30)
|
||||
{
|
||||
dds_entity_t pub_topic;
|
||||
dds_entity_t sub_topic;
|
||||
dds_entity_t reader;
|
||||
dds_entity_t writer;
|
||||
seqno_t start_seqno, end_seqno;
|
||||
dds_qos_t *rqos;
|
||||
dds_qos_t *wqos;
|
||||
dds_entity_t waitset;
|
||||
dds_attach_t triggered;
|
||||
uint32_t status;
|
||||
char name[100];
|
||||
dds_time_t t;
|
||||
|
||||
t = dds_time();
|
||||
printf("%d.%06d running test: kind %s, lease duration %d, delay %d\n",
|
||||
(int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000,
|
||||
kind == 0 ? "A" : "MP", ldur, (int32_t)(mult * ldur));
|
||||
|
||||
/* wait for initial PMD to be sent by the participant */
|
||||
while (get_pmd_seqno(g_pub_participant) < 1)
|
||||
dds_sleepfor(DDS_MSECS(50));
|
||||
|
||||
/* topics */
|
||||
create_topic_name("ddsc_liveliness_pmd_count", g_topic_nr++, name, sizeof name);
|
||||
CU_ASSERT_FATAL((pub_topic = dds_create_topic(g_pub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0);
|
||||
CU_ASSERT_FATAL((sub_topic = dds_create_topic(g_sub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0);
|
||||
|
||||
/* reader */
|
||||
CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL);
|
||||
dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY);
|
||||
CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0);
|
||||
dds_delete_qos(rqos);
|
||||
CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
|
||||
|
||||
/* waitset on reader */
|
||||
CU_ASSERT_FATAL((waitset = dds_create_waitset(g_sub_participant)) > 0);
|
||||
CU_ASSERT_EQUAL_FATAL(dds_waitset_attach(waitset, reader, reader), DDS_RETCODE_OK);
|
||||
|
||||
/* writer */
|
||||
CU_ASSERT_FATAL((wqos = dds_create_qos()) != NULL);
|
||||
dds_qset_liveliness(wqos, kind, DDS_MSECS(ldur));
|
||||
CU_ASSERT_FATAL((writer = dds_create_writer(g_pub_participant, pub_topic, wqos, NULL)) > 0);
|
||||
dds_delete_qos(wqos);
|
||||
|
||||
/* wait for writer to be alive */
|
||||
CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_SECS(1)), 1);
|
||||
CU_ASSERT_EQUAL_FATAL(dds_take_status(reader, &status, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
|
||||
|
||||
/* check no of PMD messages sent */
|
||||
start_seqno = get_pmd_seqno(g_pub_participant);
|
||||
dds_sleepfor(DDS_MSECS((dds_duration_t)(mult * ldur)));
|
||||
end_seqno = get_pmd_seqno(g_pub_participant);
|
||||
|
||||
t = dds_time();
|
||||
printf("%d.%06d PMD sequence no: start %" PRId64 " -> end %" PRId64 "\n",
|
||||
(int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000,
|
||||
start_seqno, end_seqno);
|
||||
|
||||
/* End-start should be mult - 1 under ideal circumstances, but consider the test successful
|
||||
when at least 50% of the expected PMD's was sent. This checks that the frequency for sending
|
||||
PMDs was increased when the writer was added. */
|
||||
CU_ASSERT(end_seqno - start_seqno >= (kind == DDS_LIVELINESS_AUTOMATIC ? (50 * (mult - 1)) / 100 : 0))
|
||||
if (kind != DDS_LIVELINESS_AUTOMATIC)
|
||||
CU_ASSERT(get_pmd_seqno(g_pub_participant) - start_seqno < mult)
|
||||
|
||||
/* cleanup */
|
||||
CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK);
|
||||
CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK);
|
||||
CU_ASSERT_EQUAL_FATAL(dds_delete(writer), DDS_RETCODE_OK);
|
||||
CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that the expected number of proxy writers expires (set to not-alive)
|
||||
* after a certain delay for various combinations of writers with different
|
||||
* liveliness kinds.
|
||||
*/
|
||||
CU_TheoryDataPoints(ddsc_liveliness, expire_liveliness_kinds) = {
|
||||
CU_DataPoints(uint32_t, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200), /* lease duration for initial test run (increased for each retry when test fails) */
|
||||
CU_DataPoints(double, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 2, 2, 2, 2, 2, 2, 2, 2, 2), /* delay (n times lease duration) */
|
||||
CU_DataPoints(uint32_t, 1, 0, 2, 0, 1, 0, 0, 1, 1, 2, 0, 5, 0, 15, 15), /* number of writers with automatic liveliness */
|
||||
CU_DataPoints(uint32_t, 1, 1, 2, 2, 0, 0, 0, 1, 0, 2, 2, 5, 10, 0, 15), /* number of writers with manual-by-participant liveliness */
|
||||
CU_DataPoints(uint32_t, 1, 1, 2, 2, 1, 1, 1, 1, 0, 1, 1, 2, 5, 0, 10), /* number of writers with manual-by-topic liveliness */
|
||||
};
|
||||
CU_Theory((uint32_t ldur, double mult, uint32_t wr_cnt_auto, uint32_t wr_cnt_man_pp, uint32_t wr_cnt_man_tp), ddsc_liveliness, expire_liveliness_kinds, .init = liveliness_init, .fini = liveliness_fini, .timeout = 120)
|
||||
{
|
||||
dds_entity_t pub_topic;
|
||||
dds_entity_t sub_topic;
|
||||
dds_entity_t reader;
|
||||
dds_entity_t *writers;
|
||||
dds_qos_t *rqos, *wqos_auto, *wqos_man_pp, *wqos_man_tp;
|
||||
dds_entity_t waitset;
|
||||
dds_attach_t triggered;
|
||||
struct dds_liveliness_changed_status lstatus;
|
||||
uint32_t status, n, run = 1, wr_cnt = wr_cnt_auto + wr_cnt_man_pp + wr_cnt_man_tp;
|
||||
char name[100];
|
||||
dds_time_t tstart, t;
|
||||
bool test_finished = false;
|
||||
|
||||
do
|
||||
{
|
||||
tstart = dds_time();
|
||||
printf("%d.%06d running test: lease duration %d, delay %f, auto/man-by-part/man-by-topic %u/%u/%u\n",
|
||||
(int32_t)(tstart / DDS_NSECS_IN_SEC), (int32_t)(tstart % DDS_NSECS_IN_SEC) / 1000,
|
||||
ldur, mult, wr_cnt_auto, wr_cnt_man_pp, wr_cnt_man_tp);
|
||||
|
||||
/* topics */
|
||||
create_topic_name("ddsc_liveliness_expire_kinds", g_topic_nr++, name, sizeof name);
|
||||
CU_ASSERT_FATAL((pub_topic = dds_create_topic(g_pub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0);
|
||||
CU_ASSERT_FATAL((sub_topic = dds_create_topic(g_sub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0);
|
||||
|
||||
/* reader */
|
||||
CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL);
|
||||
dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY);
|
||||
CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0);
|
||||
dds_delete_qos(rqos);
|
||||
CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
|
||||
|
||||
/* writers */
|
||||
CU_ASSERT_FATAL((wqos_auto = dds_create_qos()) != NULL);
|
||||
dds_qset_liveliness(wqos_auto, DDS_LIVELINESS_AUTOMATIC, DDS_MSECS(ldur));
|
||||
CU_ASSERT_FATAL((wqos_man_pp = dds_create_qos()) != NULL);
|
||||
dds_qset_liveliness(wqos_man_pp, DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, DDS_MSECS(ldur));
|
||||
CU_ASSERT_FATAL((wqos_man_tp = dds_create_qos()) != NULL);
|
||||
dds_qset_liveliness(wqos_man_tp, DDS_LIVELINESS_MANUAL_BY_TOPIC, DDS_MSECS(ldur));
|
||||
|
||||
CU_ASSERT_FATAL((waitset = dds_create_waitset(g_sub_participant)) > 0);
|
||||
CU_ASSERT_EQUAL_FATAL(dds_waitset_attach(waitset, reader, reader), DDS_RETCODE_OK);
|
||||
|
||||
writers = dds_alloc(wr_cnt * sizeof(dds_entity_t));
|
||||
for (n = 0; n < wr_cnt; n++)
|
||||
{
|
||||
dds_qos_t *wqos;
|
||||
wqos = n < wr_cnt_auto ? wqos_auto : (n < (wr_cnt_auto + wr_cnt_man_pp) ? wqos_man_pp : wqos_man_tp);
|
||||
CU_ASSERT_FATAL((writers[n] = dds_create_writer(g_pub_participant, pub_topic, wqos, NULL)) > 0);
|
||||
CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_SECS(5)), 1);
|
||||
CU_ASSERT_EQUAL_FATAL(dds_take_status(reader, &status, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
|
||||
}
|
||||
dds_delete_qos(wqos_auto);
|
||||
dds_delete_qos(wqos_man_pp);
|
||||
dds_delete_qos(wqos_man_tp);
|
||||
|
||||
t = dds_time();
|
||||
if (t - tstart > DDS_MSECS(0.5 * ldur))
|
||||
{
|
||||
ldur *= 10 / (run + 1);
|
||||
printf("%d.%06d failed to create writers in time\n",
|
||||
(int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* check alive count before proxy writers are expired */
|
||||
dds_get_liveliness_changed_status(reader, &lstatus);
|
||||
printf("%d.%06d writers alive: %d\n", (int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000, lstatus.alive_count);
|
||||
CU_ASSERT_EQUAL_FATAL(lstatus.alive_count, wr_cnt);
|
||||
|
||||
dds_time_t tstop = tstart + DDS_MSECS((dds_duration_t)(mult * ldur));
|
||||
uint32_t stopped = 0;
|
||||
do
|
||||
{
|
||||
dds_duration_t w = tstop - dds_time();
|
||||
CU_ASSERT_FATAL((dds_waitset_wait(waitset, &triggered, 1, w > 0 ? w : 0)) >= 0);
|
||||
CU_ASSERT_EQUAL_FATAL(dds_get_liveliness_changed_status(reader, &lstatus), DDS_RETCODE_OK);
|
||||
stopped += (uint32_t)lstatus.not_alive_count_change;
|
||||
} while (dds_time() < tstop);
|
||||
t = dds_time();
|
||||
printf("%d.%06d writers stopped: %u\n",
|
||||
(int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000, stopped);
|
||||
|
||||
size_t exp_stopped = mult < 1 ? 0 : (wr_cnt_man_pp + wr_cnt_man_tp);
|
||||
if (stopped != exp_stopped)
|
||||
{
|
||||
ldur *= 10 / (run + 1);
|
||||
printf("%d.%06d incorrect number of stopped writers\n",
|
||||
(int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* check alive count */
|
||||
CU_ASSERT_EQUAL_FATAL(dds_get_liveliness_changed_status(reader, &lstatus), DDS_RETCODE_OK);
|
||||
CU_ASSERT_EQUAL(lstatus.alive_count, mult < 1 ? wr_cnt : wr_cnt_auto);
|
||||
test_finished = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* cleanup */
|
||||
CU_ASSERT_EQUAL_FATAL(dds_waitset_detach(waitset, reader), DDS_RETCODE_OK);
|
||||
CU_ASSERT_EQUAL_FATAL(dds_delete(waitset), DDS_RETCODE_OK);
|
||||
|
||||
for (n = 0; n < wr_cnt; n++)
|
||||
CU_ASSERT_EQUAL_FATAL(dds_delete(writers[n]), DDS_RETCODE_OK);
|
||||
dds_free(writers);
|
||||
CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK);
|
||||
CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK);
|
||||
CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK);
|
||||
|
||||
if (!test_finished)
|
||||
{
|
||||
if (++run > 3)
|
||||
{
|
||||
printf("%d.%06d run limit reached, test failed\n", (int32_t)(tstart / DDS_NSECS_IN_SEC), (int32_t)(tstart % DDS_NSECS_IN_SEC) / 1000);
|
||||
CU_FAIL_FATAL("Run limit reached");
|
||||
test_finished = true;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("%d.%06d restarting test with ldur %d\n",
|
||||
(int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000, ldur);
|
||||
}
|
||||
}
|
||||
} while (!test_finished);
|
||||
}
|
||||
|
||||
static void add_and_check_writer(dds_liveliness_kind_t kind, dds_duration_t ldur, dds_entity_t *writer, dds_entity_t topic, dds_entity_t reader)
|
||||
{
|
||||
dds_entity_t waitset;
|
||||
dds_qos_t *wqos;
|
||||
dds_attach_t triggered;
|
||||
uint32_t status;
|
||||
|
||||
CU_ASSERT_FATAL((waitset = dds_create_waitset(g_sub_participant)) > 0);
|
||||
CU_ASSERT_EQUAL_FATAL(dds_waitset_attach(waitset, reader, reader), DDS_RETCODE_OK);
|
||||
|
||||
CU_ASSERT_FATAL((wqos = dds_create_qos()) != NULL);
|
||||
dds_qset_liveliness(wqos, kind, ldur);
|
||||
CU_ASSERT_FATAL((*writer = dds_create_writer(g_pub_participant, topic, wqos, NULL)) > 0);
|
||||
dds_delete_qos(wqos);
|
||||
|
||||
/* wait for writer to be alive */
|
||||
CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_MSECS(1000)), 1);
|
||||
CU_ASSERT_EQUAL_FATAL(dds_take_status(reader, &status, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
|
||||
|
||||
CU_ASSERT_EQUAL_FATAL(dds_waitset_detach(waitset, reader), DDS_RETCODE_OK);
|
||||
CU_ASSERT_EQUAL_FATAL(dds_delete(waitset), DDS_RETCODE_OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that the correct PMD interval is set for the participant
|
||||
* based on the lease duration of the writers.
|
||||
*/
|
||||
#define MAX_WRITERS 10
|
||||
CU_Test(ddsc_liveliness, lease_duration, .init = liveliness_init, .fini = liveliness_fini)
|
||||
{
|
||||
dds_entity_t pub_topic;
|
||||
dds_entity_t sub_topic;
|
||||
dds_entity_t reader;
|
||||
dds_entity_t writers[MAX_WRITERS];
|
||||
uint32_t wr_cnt = 0;
|
||||
char name[100];
|
||||
dds_qos_t *rqos;
|
||||
uint32_t n;
|
||||
|
||||
/* topics */
|
||||
create_topic_name("ddsc_liveliness_ldur", 1, name, sizeof name);
|
||||
CU_ASSERT_FATAL((pub_topic = dds_create_topic(g_pub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0);
|
||||
CU_ASSERT_FATAL((sub_topic = dds_create_topic(g_sub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0);
|
||||
|
||||
/* reader and waitset */
|
||||
CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL);
|
||||
dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY);
|
||||
CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0);
|
||||
dds_delete_qos(rqos);
|
||||
CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
|
||||
|
||||
/* check if pmd defaults to configured duration */
|
||||
CU_ASSERT_EQUAL_FATAL(get_pmd_interval(g_pub_participant), get_ldur_config(g_pub_participant));
|
||||
|
||||
/* create writers and check pmd interval in publishing participant */
|
||||
add_and_check_writer(DDS_LIVELINESS_AUTOMATIC, DDS_MSECS(1000), &writers[wr_cnt++], pub_topic, reader);
|
||||
CU_ASSERT_EQUAL_FATAL(get_pmd_interval(g_pub_participant), DDS_MSECS(1000));
|
||||
|
||||
add_and_check_writer(DDS_LIVELINESS_AUTOMATIC, DDS_MSECS(2000), &writers[wr_cnt++], pub_topic, reader);
|
||||
CU_ASSERT_EQUAL_FATAL(get_pmd_interval(g_pub_participant), DDS_MSECS(1000));
|
||||
|
||||
add_and_check_writer(DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, DDS_MSECS(2000), &writers[wr_cnt++], pub_topic, reader);
|
||||
CU_ASSERT_EQUAL_FATAL(get_pmd_interval(g_pub_participant), DDS_MSECS(1000));
|
||||
|
||||
add_and_check_writer(DDS_LIVELINESS_AUTOMATIC, DDS_MSECS(500), &writers[wr_cnt++], pub_topic, reader);
|
||||
CU_ASSERT_EQUAL_FATAL(get_pmd_interval(g_pub_participant), DDS_MSECS(500));
|
||||
|
||||
add_and_check_writer(DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, DDS_MSECS(100), &writers[wr_cnt++], pub_topic, reader);
|
||||
CU_ASSERT_EQUAL_FATAL(get_pmd_interval(g_pub_participant), DDS_MSECS(500));
|
||||
|
||||
add_and_check_writer(DDS_LIVELINESS_MANUAL_BY_TOPIC, DDS_MSECS(100), &writers[wr_cnt++], pub_topic, reader);
|
||||
CU_ASSERT_EQUAL_FATAL(get_pmd_interval(g_pub_participant), DDS_MSECS(500));
|
||||
|
||||
/* cleanup */
|
||||
for (n = 0; n < wr_cnt; n++)
|
||||
CU_ASSERT_EQUAL_FATAL(dds_delete(writers[n]), DDS_RETCODE_OK);
|
||||
CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK);
|
||||
CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK);
|
||||
CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK);
|
||||
}
|
||||
#undef MAX_WRITERS
|
||||
|
||||
/**
|
||||
* Check that the correct lease duration is set in the matched
|
||||
* publications in the readers. */
|
||||
CU_Test(ddsc_liveliness, lease_duration_pwr, .init = liveliness_init, .fini = liveliness_fini)
|
||||
{
|
||||
dds_entity_t pub_topic;
|
||||
dds_entity_t sub_topic;
|
||||
dds_entity_t reader;
|
||||
dds_entity_t writer;
|
||||
char name[100];
|
||||
dds_qos_t *rqos, *wqos;
|
||||
dds_entity_t waitset;
|
||||
dds_attach_t triggered;
|
||||
uint32_t status;
|
||||
dds_duration_t ldur;
|
||||
|
||||
/* topics */
|
||||
create_topic_name("ddsc_liveliness_ldurpwr", 1, name, sizeof name);
|
||||
CU_ASSERT_FATAL((pub_topic = dds_create_topic(g_pub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0);
|
||||
CU_ASSERT_FATAL((sub_topic = dds_create_topic(g_sub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0);
|
||||
|
||||
/* reader */
|
||||
CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL);
|
||||
dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY);
|
||||
CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0);
|
||||
dds_delete_qos(rqos);
|
||||
CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
|
||||
|
||||
/* writer */
|
||||
ldur = 1000;
|
||||
CU_ASSERT_FATAL((wqos = dds_create_qos()) != NULL);
|
||||
dds_qset_liveliness(wqos, DDS_LIVELINESS_AUTOMATIC, DDS_MSECS(ldur));
|
||||
CU_ASSERT_FATAL((writer = dds_create_writer(g_pub_participant, pub_topic, wqos, NULL)) > 0);
|
||||
|
||||
/* wait for writer to be alive */
|
||||
CU_ASSERT_FATAL((waitset = dds_create_waitset(g_sub_participant)) > 0);
|
||||
CU_ASSERT_EQUAL_FATAL(dds_waitset_attach(waitset, reader, reader), DDS_RETCODE_OK);
|
||||
CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_MSECS(1000)), 1);
|
||||
CU_ASSERT_EQUAL_FATAL(dds_take_status(reader, &status, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
|
||||
|
||||
/* check pwr lease duration in matched publication */
|
||||
dds_instance_handle_t wrs[1];
|
||||
CU_ASSERT_EQUAL_FATAL(dds_get_matched_publications(reader, wrs, 1), 1);
|
||||
dds_builtintopic_endpoint_t *ep;
|
||||
ep = dds_get_matched_publication_data(reader, wrs[0]);
|
||||
CU_ASSERT_FATAL(ep != NULL);
|
||||
assert(ep != NULL); /* for Clang's static analyzer */
|
||||
CU_ASSERT_EQUAL_FATAL(ep->qos->liveliness.lease_duration, DDS_MSECS(ldur));
|
||||
dds_delete_qos(ep->qos);
|
||||
dds_free(ep->topic_name);
|
||||
dds_free(ep->type_name);
|
||||
dds_free(ep);
|
||||
|
||||
/* cleanup */
|
||||
dds_delete_qos(wqos);
|
||||
CU_ASSERT_EQUAL_FATAL(dds_waitset_detach(waitset, reader), DDS_RETCODE_OK);
|
||||
CU_ASSERT_EQUAL_FATAL(dds_delete(waitset), DDS_RETCODE_OK);
|
||||
CU_ASSERT_EQUAL_FATAL(dds_delete(writer), DDS_RETCODE_OK);
|
||||
CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK);
|
||||
CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK);
|
||||
CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a relative large number of writers with liveliness kinds automatic and
|
||||
* manual-by-participant and with decreasing lease duration, and check that all
|
||||
* writers become alive. During the writer creation loop, every third writer
|
||||
* is deleted immediately after creating.
|
||||
*/
|
||||
#define MAX_WRITERS 100
|
||||
CU_Test(ddsc_liveliness, create_delete_writer_stress, .init = liveliness_init, .fini = liveliness_fini, .timeout = 15)
|
||||
{
|
||||
dds_entity_t pub_topic;
|
||||
dds_entity_t sub_topic;
|
||||
dds_entity_t reader;
|
||||
dds_entity_t writers[MAX_WRITERS];
|
||||
dds_entity_t waitset;
|
||||
dds_qos_t *wqos;
|
||||
struct dds_liveliness_changed_status lstatus;
|
||||
uint32_t alive_writers_auto = 0, alive_writers_man = 0;
|
||||
char name[100];
|
||||
dds_qos_t *rqos;
|
||||
dds_attach_t triggered;
|
||||
uint32_t n;
|
||||
Space_Type1 sample = {0, 0, 0};
|
||||
int64_t ldur = 1000;
|
||||
|
||||
/* topics */
|
||||
create_topic_name("ddsc_liveliness_wr_stress", 1, name, sizeof name);
|
||||
CU_ASSERT_FATAL((pub_topic = dds_create_topic(g_pub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0);
|
||||
CU_ASSERT_FATAL((sub_topic = dds_create_topic(g_sub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0);
|
||||
|
||||
/* reader and waitset */
|
||||
CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL);
|
||||
dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY);
|
||||
CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0);
|
||||
dds_delete_qos(rqos);
|
||||
CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
|
||||
CU_ASSERT_FATAL((waitset = dds_create_waitset(g_sub_participant)) > 0);
|
||||
CU_ASSERT_EQUAL_FATAL(dds_waitset_attach(waitset, reader, reader), DDS_RETCODE_OK);
|
||||
|
||||
/* create 1st writer and wait for it to become alive */
|
||||
CU_ASSERT_FATAL((wqos = dds_create_qos()) != NULL);
|
||||
dds_qset_liveliness(wqos, DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, DDS_MSECS(ldur));
|
||||
CU_ASSERT_FATAL((writers[0] = dds_create_writer(g_pub_participant, pub_topic, wqos, NULL)) > 0);
|
||||
CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_MSECS(1000)), 1);
|
||||
alive_writers_man++;
|
||||
|
||||
/* create writers */
|
||||
for (n = 1; n < MAX_WRITERS; n++)
|
||||
{
|
||||
dds_qset_liveliness(wqos, n % 2 ? DDS_LIVELINESS_AUTOMATIC : DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, DDS_MSECS(n % 3 ? ldur + n : ldur - n) + ((n % 3) == 2 ? 1 : 0));
|
||||
CU_ASSERT_FATAL((writers[n] = dds_create_writer(g_pub_participant, pub_topic, wqos, NULL)) > 0);
|
||||
dds_write(writers[n], &sample);
|
||||
if (n % 3 == 2)
|
||||
dds_delete(writers[n]);
|
||||
else if (n % 2)
|
||||
alive_writers_auto++;
|
||||
else
|
||||
alive_writers_man++;
|
||||
}
|
||||
dds_delete_qos(wqos);
|
||||
printf("alive_writers_auto: %d, alive_writers_man: %d\n", alive_writers_auto, alive_writers_man);
|
||||
|
||||
/* wait for auto liveliness writers to become alive and manual-by-pp writers to become not-alive */
|
||||
do
|
||||
{
|
||||
CU_ASSERT_EQUAL_FATAL(dds_get_liveliness_changed_status(reader, &lstatus), DDS_RETCODE_OK);
|
||||
printf("alive: %d, not-alive: %d\n", lstatus.alive_count, lstatus.not_alive_count);
|
||||
dds_sleepfor(DDS_MSECS(50));
|
||||
} while (lstatus.alive_count != alive_writers_auto || lstatus.not_alive_count != alive_writers_man);
|
||||
|
||||
/* check that counts are stable after a delay */
|
||||
dds_sleepfor(DDS_MSECS(ldur / 2));
|
||||
CU_ASSERT_EQUAL_FATAL(dds_get_liveliness_changed_status(reader, &lstatus), DDS_RETCODE_OK);
|
||||
CU_ASSERT_FATAL(lstatus.alive_count == alive_writers_auto && lstatus.not_alive_count == alive_writers_man);
|
||||
|
||||
/* cleanup remaining writers */
|
||||
for (n = 0; n < MAX_WRITERS; n++)
|
||||
{
|
||||
if (n % 3 != 2)
|
||||
CU_ASSERT_EQUAL_FATAL(dds_delete(writers[n]), DDS_RETCODE_OK);
|
||||
}
|
||||
/* wait for alive_count and not_alive_count to become 0 */
|
||||
do
|
||||
{
|
||||
CU_ASSERT_EQUAL_FATAL(dds_get_liveliness_changed_status(reader, &lstatus), DDS_RETCODE_OK);
|
||||
printf("alive: %d, not: %d\n", lstatus.alive_count, lstatus.not_alive_count);
|
||||
dds_sleepfor(DDS_MSECS(ldur / 10));
|
||||
} while (lstatus.alive_count > 0 || lstatus.not_alive_count > 0);
|
||||
CU_ASSERT_EQUAL_FATAL(dds_waitset_detach(waitset, reader), DDS_RETCODE_OK);
|
||||
CU_ASSERT_EQUAL_FATAL(dds_delete(waitset), DDS_RETCODE_OK);
|
||||
CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK);
|
||||
CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK);
|
||||
CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK);
|
||||
}
|
||||
#undef MAX_WRITERS
|
||||
|
||||
/**
|
||||
* Check the counts in liveliness_changed_status result.
|
||||
*/
|
||||
CU_Test(ddsc_liveliness, status_counts, .init = liveliness_init, .fini = liveliness_fini)
|
||||
{
|
||||
dds_entity_t pub_topic;
|
||||
dds_entity_t sub_topic;
|
||||
dds_entity_t reader;
|
||||
dds_entity_t writer;
|
||||
dds_entity_t waitset;
|
||||
dds_qos_t *rqos;
|
||||
dds_qos_t *wqos;
|
||||
dds_attach_t triggered;
|
||||
struct dds_liveliness_changed_status lstatus;
|
||||
struct dds_subscription_matched_status sstatus;
|
||||
char name[100];
|
||||
dds_duration_t ldur = DDS_MSECS(500);
|
||||
Space_Type1 sample = {1, 0, 0};
|
||||
|
||||
/* topics */
|
||||
create_topic_name("ddsc_liveliness_status_counts", g_topic_nr++, name, sizeof name);
|
||||
CU_ASSERT_FATAL((pub_topic = dds_create_topic(g_pub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0);
|
||||
CU_ASSERT_FATAL((sub_topic = dds_create_topic(g_sub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0);
|
||||
|
||||
/* reader */
|
||||
CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL);
|
||||
dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY);
|
||||
CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0);
|
||||
dds_delete_qos(rqos);
|
||||
CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
|
||||
CU_ASSERT_FATAL((waitset = dds_create_waitset(g_sub_participant)) > 0);
|
||||
CU_ASSERT_EQUAL_FATAL(dds_waitset_attach(waitset, reader, reader), DDS_RETCODE_OK);
|
||||
|
||||
/* writer */
|
||||
CU_ASSERT_FATAL((wqos = dds_create_qos()) != NULL);
|
||||
dds_qset_liveliness(wqos, DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, ldur);
|
||||
CU_ASSERT_FATAL((writer = dds_create_writer(g_pub_participant, pub_topic, wqos, NULL)) > 0);
|
||||
dds_delete_qos(wqos);
|
||||
|
||||
/* wait for writer to be alive */
|
||||
CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_SECS(5)), 1);
|
||||
|
||||
/* check status counts before proxy writer is expired */
|
||||
dds_get_liveliness_changed_status(reader, &lstatus);
|
||||
CU_ASSERT_EQUAL_FATAL(lstatus.alive_count, 1);
|
||||
dds_get_subscription_matched_status(reader, &sstatus);
|
||||
CU_ASSERT_EQUAL_FATAL(sstatus.current_count, 1);
|
||||
|
||||
/* sleep for more than lease duration, writer should be set not-alive but subscription still matched */
|
||||
dds_sleepfor(ldur + DDS_MSECS(100));
|
||||
CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_SECS(5)), 1);
|
||||
|
||||
dds_get_liveliness_changed_status(reader, &lstatus);
|
||||
CU_ASSERT_EQUAL_FATAL(lstatus.alive_count, 0);
|
||||
dds_get_subscription_matched_status(reader, &sstatus);
|
||||
CU_ASSERT_EQUAL_FATAL(sstatus.current_count, 1);
|
||||
|
||||
/* write sample and re-check status counts */
|
||||
dds_write(writer, &sample);
|
||||
CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_SECS(5)), 1);
|
||||
|
||||
dds_get_liveliness_changed_status(reader, &lstatus);
|
||||
CU_ASSERT_EQUAL_FATAL(lstatus.alive_count, 1);
|
||||
dds_get_subscription_matched_status(reader, &sstatus);
|
||||
CU_ASSERT_EQUAL_FATAL(sstatus.current_count, 1);
|
||||
|
||||
/* cleanup */
|
||||
CU_ASSERT_EQUAL_FATAL(dds_waitset_detach(waitset, reader), DDS_RETCODE_OK);
|
||||
CU_ASSERT_EQUAL_FATAL(dds_delete(waitset), DDS_RETCODE_OK);
|
||||
CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK);
|
||||
CU_ASSERT_EQUAL_FATAL(dds_delete(writer), DDS_RETCODE_OK);
|
||||
CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK);
|
||||
CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that dds_assert_liveliness works as expected for liveliness
|
||||
* kinds manual-by-participant and manual-by-topic.
|
||||
*/
|
||||
#define MAX_WRITERS 100
|
||||
CU_TheoryDataPoints(ddsc_liveliness, assert_liveliness) = {
|
||||
CU_DataPoints(uint32_t, 1, 0, 0, 1), /* number of writers with automatic liveliness */
|
||||
CU_DataPoints(uint32_t, 1, 1, 0, 0), /* number of writers with manual-by-participant liveliness */
|
||||
CU_DataPoints(uint32_t, 1, 1, 1, 2), /* number of writers with manual-by-topic liveliness */
|
||||
};
|
||||
CU_Theory((uint32_t wr_cnt_auto, uint32_t wr_cnt_man_pp, uint32_t wr_cnt_man_tp), ddsc_liveliness, assert_liveliness, .init = liveliness_init, .fini = liveliness_fini, .timeout = 60)
|
||||
{
|
||||
dds_entity_t pub_topic, sub_topic, reader, writers[MAX_WRITERS];
|
||||
dds_qos_t *rqos;
|
||||
struct dds_liveliness_changed_status lstatus;
|
||||
char name[100];
|
||||
uint32_t ldur = 100, wr_cnt, run = 1, stopped;
|
||||
dds_time_t tstart, tstop, t;
|
||||
bool test_finished = false;
|
||||
|
||||
do
|
||||
{
|
||||
wr_cnt = 0;
|
||||
assert(wr_cnt_auto + wr_cnt_man_pp + wr_cnt_man_tp < MAX_WRITERS);
|
||||
printf("running test assert_liveliness: auto/man-by-part/man-by-topic %u/%u/%u with ldur %d\n",
|
||||
wr_cnt_auto, wr_cnt_man_pp, wr_cnt_man_tp, ldur);
|
||||
|
||||
/* topics */
|
||||
create_topic_name("ddsc_liveliness_assert", g_topic_nr++, name, sizeof name);
|
||||
CU_ASSERT_FATAL((pub_topic = dds_create_topic(g_pub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0);
|
||||
CU_ASSERT_FATAL((sub_topic = dds_create_topic(g_sub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0);
|
||||
|
||||
/* reader */
|
||||
CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL);
|
||||
dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY);
|
||||
CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0);
|
||||
dds_delete_qos(rqos);
|
||||
CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
|
||||
|
||||
/* writers */
|
||||
for (size_t n = 0; n < wr_cnt_auto; n++)
|
||||
add_and_check_writer(DDS_LIVELINESS_AUTOMATIC, DDS_MSECS(ldur), &writers[wr_cnt++], pub_topic, reader);
|
||||
tstart = dds_time();
|
||||
for (size_t n = 0; n < wr_cnt_man_pp; n++)
|
||||
add_and_check_writer(DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, DDS_MSECS(ldur), &writers[wr_cnt++], pub_topic, reader);
|
||||
for (size_t n = 0; n < wr_cnt_man_tp; n++)
|
||||
add_and_check_writer(DDS_LIVELINESS_MANUAL_BY_TOPIC, DDS_MSECS(ldur), &writers[wr_cnt++], pub_topic, reader);
|
||||
t = dds_time();
|
||||
if (t - tstart > DDS_MSECS(0.5 * ldur))
|
||||
{
|
||||
ldur *= 10 / (run + 1);
|
||||
printf("%d.%06d failed to create writers with non-automatic liveliness kind in time\n",
|
||||
(int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* check status counts before proxy writer is expired */
|
||||
dds_get_liveliness_changed_status(reader, &lstatus);
|
||||
CU_ASSERT_EQUAL_FATAL(lstatus.alive_count, wr_cnt_auto + wr_cnt_man_pp + wr_cnt_man_tp);
|
||||
|
||||
/* delay for more than lease duration and assert liveliness on writers:
|
||||
all writers (including man-by-pp) should be kept alive */
|
||||
tstop = dds_time() + 4 * DDS_MSECS(ldur) / 3;
|
||||
stopped = 0;
|
||||
do
|
||||
{
|
||||
for (size_t n = wr_cnt - wr_cnt_man_tp; n < wr_cnt; n++)
|
||||
dds_assert_liveliness(writers[n]);
|
||||
CU_ASSERT_EQUAL_FATAL(dds_get_liveliness_changed_status(reader, &lstatus), DDS_RETCODE_OK);
|
||||
stopped += (uint32_t)lstatus.not_alive_count_change;
|
||||
dds_sleepfor(DDS_MSECS(50));
|
||||
} while (dds_time() < tstop);
|
||||
dds_get_liveliness_changed_status(reader, &lstatus);
|
||||
printf("writers alive with dds_assert_liveliness on all writers: %d, writers stopped: %d\n", lstatus.alive_count, stopped);
|
||||
if (lstatus.alive_count != wr_cnt_auto + wr_cnt_man_pp + wr_cnt_man_tp || stopped != 0)
|
||||
{
|
||||
ldur *= 10 / (run + 1);
|
||||
printf("incorrect number of writers alive or stopped writers\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
/* delay for more than lease duration and assert liveliness on participant:
|
||||
writers with liveliness man-by-pp should be kept alive, man-by-topic writers
|
||||
should stop */
|
||||
tstop = dds_time() + 4 * DDS_MSECS(ldur) / 3;
|
||||
stopped = 0;
|
||||
do
|
||||
{
|
||||
dds_assert_liveliness(g_pub_participant);
|
||||
CU_ASSERT_EQUAL_FATAL(dds_get_liveliness_changed_status(reader, &lstatus), DDS_RETCODE_OK);
|
||||
stopped += (uint32_t)lstatus.not_alive_count_change;
|
||||
dds_sleepfor(DDS_MSECS(50));
|
||||
} while (dds_time() < tstop);
|
||||
dds_get_liveliness_changed_status(reader, &lstatus);
|
||||
printf("writers alive with dds_assert_liveliness on participant: %d, writers stopped: %d\n", lstatus.alive_count, stopped);
|
||||
if (lstatus.alive_count != wr_cnt_auto + wr_cnt_man_pp || stopped != wr_cnt_man_tp)
|
||||
{
|
||||
ldur *= 10 / (run + 1);
|
||||
printf("incorrect number of writers alive or stopped writers\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
test_finished = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* cleanup */
|
||||
CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK);
|
||||
for (size_t n = 0; n < wr_cnt; n++)
|
||||
CU_ASSERT_EQUAL_FATAL(dds_delete(writers[n]), DDS_RETCODE_OK);
|
||||
CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK);
|
||||
CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK);
|
||||
|
||||
if (!test_finished)
|
||||
{
|
||||
if (++run > 3)
|
||||
{
|
||||
CU_FAIL_FATAL("Run limit reached");
|
||||
test_finished = true;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("restarting test with ldur %d\n", ldur);
|
||||
}
|
||||
}
|
||||
} while (!test_finished);
|
||||
}
|
||||
#undef MAX_WRITERS
|
Loading…
Add table
Add a link
Reference in a new issue