Merge branch 'master' into merge
Signed-off-by: Martin Bremmer <martin.bremmer@adlinktech.com>
This commit is contained in:
		
						commit
						919850232c
					
				
					 128 changed files with 6936 additions and 2075 deletions
				
			
		| 
						 | 
				
			
			@ -50,6 +50,7 @@ PREPEND(hdrs_public_ddsc "$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include/dd
 | 
			
		|||
    ddsc/dds_public_qos.h
 | 
			
		||||
    ddsc/dds_public_qosdefs.h
 | 
			
		||||
    ddsc/dds_public_status.h
 | 
			
		||||
    ddsc/dds_rhc.h
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
PREPEND(hdrs_private_ddsc "${CMAKE_CURRENT_LIST_DIR}/src"
 | 
			
		||||
| 
						 | 
				
			
			@ -67,7 +68,6 @@ PREPEND(hdrs_private_ddsc "${CMAKE_CURRENT_LIST_DIR}/src"
 | 
			
		|||
    dds__readcond.h
 | 
			
		||||
    dds__guardcond.h
 | 
			
		||||
    dds__reader.h
 | 
			
		||||
    dds__rhc.h
 | 
			
		||||
    dds__rhc_default.h
 | 
			
		||||
    dds__stream.h
 | 
			
		||||
    dds__subscriber.h
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -49,19 +49,9 @@ typedef int32_t dds_entity_t;
 | 
			
		|||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
struct dds_rhc;
 | 
			
		||||
struct ddsi_serdata;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Returns the default domain identifier.
 | 
			
		||||
 *
 | 
			
		||||
 * The default domain identifier can be configured in the configuration file
 | 
			
		||||
 * or be set through an evironment variable ({DDSC_PROJECT_NAME_NOSPACE_CAPS}_DOMAIN).
 | 
			
		||||
 *
 | 
			
		||||
 * @returns Default domain identifier
 | 
			
		||||
 */
 | 
			
		||||
DDS_EXPORT dds_domainid_t dds_domain_default (void);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define DDS_MIN_PSEUDO_HANDLE ((dds_entity_t) 0x7fff0000)
 | 
			
		||||
 | 
			
		||||
/* @defgroup builtintopic_constants Convenience constants for referring to builtin topics
 | 
			
		||||
| 
						 | 
				
			
			@ -77,6 +67,9 @@ DDS_EXPORT dds_domainid_t dds_domain_default (void);
 | 
			
		|||
#define DDS_BUILTIN_TOPIC_DCPSSUBSCRIPTION ((dds_entity_t) (DDS_MIN_PSEUDO_HANDLE + 4))
 | 
			
		||||
/** @}*/
 | 
			
		||||
 | 
			
		||||
/** Special handle representing the entity corresponding to the CycloneDDS library itself */
 | 
			
		||||
#define DDS_CYCLONEDDS_HANDLE              ((dds_entity_t) (DDS_MIN_PSEUDO_HANDLE + 256))
 | 
			
		||||
 | 
			
		||||
/** @name Communication Status definitions
 | 
			
		||||
  @{**/
 | 
			
		||||
typedef enum dds_status_id {
 | 
			
		||||
| 
						 | 
				
			
			@ -733,7 +726,7 @@ dds_set_listener(dds_entity_t entity, const dds_listener_t * listener);
 | 
			
		|||
 * If no configuration file exists, the default domain is configured as 0.
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 * @param[in]  domain The domain in which to create the participant (can be DDS_DOMAIN_DEFAULT). Valid values for domain id are between 0 and 230. DDS_DOMAIN_DEFAULT is for using the domain in the configuration.
 | 
			
		||||
 * @param[in]  domain The domain in which to create the participant (can be DDS_DOMAIN_DEFAULT). DDS_DOMAIN_DEFAULT is for using the domain in the configuration.
 | 
			
		||||
 * @param[in]  qos The QoS to set on the new participant (can be NULL).
 | 
			
		||||
 * @param[in]  listener Any listener functions associated with the new participant (can be NULL).
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -750,6 +743,33 @@ dds_create_participant(
 | 
			
		|||
  const dds_qos_t *qos,
 | 
			
		||||
  const dds_listener_t *listener);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Creates a domain with a given configuration
 | 
			
		||||
 *
 | 
			
		||||
 * To explicitly create a domain based on a configuration passed as a string.
 | 
			
		||||
 * Normally, the domain is created implicitly on the first call to
 | 
			
		||||
 * dds_create_particiant based on the configuration specified throught
 | 
			
		||||
 * the environment. This function allows to by-pass this behaviour.
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 * @param[in]  domain The domain to be created. DEFAULT_DOMAIN is not allowed.
 | 
			
		||||
 * @param[in]  config A configuration string containing file names and/or XML fragments representing the configuration.
 | 
			
		||||
 *
 | 
			
		||||
 * @returns A return code
 | 
			
		||||
 *
 | 
			
		||||
 * @retval DDS_RETCODE_OK
 | 
			
		||||
 *             The domain with the domain identifier has been created from
 | 
			
		||||
 *             given configuration string.
 | 
			
		||||
 * @retval DDS_RETCODE_BAD_PARAMETER
 | 
			
		||||
 *             Illegal value for domain id or the configfile parameter is NULL.
 | 
			
		||||
 * @retval DDS_PRECONDITION_NOT_MET
 | 
			
		||||
 *             The domain already existed and cannot be created again.
 | 
			
		||||
 * @retval DDS_RETCODE_ERROR
 | 
			
		||||
 *             An internal error has occurred.
 | 
			
		||||
 */
 | 
			
		||||
DDS_EXPORT dds_return_t
 | 
			
		||||
dds_create_domain(const dds_domainid_t domain, const char *config);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Get entity parent.
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			@ -871,7 +891,8 @@ dds_get_children(dds_entity_t entity, dds_entity_t *children, size_t size);
 | 
			
		|||
 * DataReaders), etc are also attached to that domain.
 | 
			
		||||
 *
 | 
			
		||||
 * This function will return the original domain ID when called on
 | 
			
		||||
 * any of the entities within that hierarchy.
 | 
			
		||||
 * any of the entities within that hierarchy.  For entities not associated
 | 
			
		||||
 * with a domain, the id is set to DDS_DOMAIN_DEFAULT.
 | 
			
		||||
 *
 | 
			
		||||
 * @param[in]  entity   Entity from which to get its children.
 | 
			
		||||
 * @param[out] id       Pointer to put the domain ID in.
 | 
			
		||||
| 
						 | 
				
			
			@ -1202,6 +1223,34 @@ dds_create_reader(
 | 
			
		|||
  const dds_qos_t *qos,
 | 
			
		||||
  const dds_listener_t *listener);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Creates a new instance of a DDS reader with a custom history cache.
 | 
			
		||||
 *
 | 
			
		||||
 * This implicit subscriber will be deleted automatically when the created reader
 | 
			
		||||
 * is deleted.
 | 
			
		||||
 *
 | 
			
		||||
 * @param[in]  participant_or_subscriber The participant or subscriber on which the reader is being created.
 | 
			
		||||
 * @param[in]  topic                     The topic to read.
 | 
			
		||||
 * @param[in]  qos                       The QoS to set on the new reader (can be NULL).
 | 
			
		||||
 * @param[in]  listener                  Any listener functions associated with the new reader (can be NULL).
 | 
			
		||||
 * @param[in]  rhc                       Reader history cache to use, reader becomes the owner
 | 
			
		||||
 *
 | 
			
		||||
 * @returns A valid reader handle or an error code.
 | 
			
		||||
 *
 | 
			
		||||
 * @retval >0
 | 
			
		||||
 *            A valid reader handle.
 | 
			
		||||
 * @retval DDS_RETCODE_ERROR
 | 
			
		||||
 *            An internal error occurred.
 | 
			
		||||
 */
 | 
			
		||||
/* TODO: Complete list of error codes */
 | 
			
		||||
DDS_EXPORT dds_entity_t
 | 
			
		||||
dds_create_reader_rhc(
 | 
			
		||||
  dds_entity_t participant_or_subscriber,
 | 
			
		||||
  dds_entity_t topic,
 | 
			
		||||
  const dds_qos_t *qos,
 | 
			
		||||
  const dds_listener_t *listener,
 | 
			
		||||
  struct dds_rhc *rhc);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Wait until reader receives all historic data
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -108,7 +108,9 @@ typedef enum dds_entity_kind
 | 
			
		|||
  DDS_KIND_COND_READ,
 | 
			
		||||
  DDS_KIND_COND_QUERY,
 | 
			
		||||
  DDS_KIND_COND_GUARD,
 | 
			
		||||
  DDS_KIND_WAITSET
 | 
			
		||||
  DDS_KIND_WAITSET,
 | 
			
		||||
  DDS_KIND_DOMAIN,
 | 
			
		||||
  DDS_KIND_CYCLONEDDS
 | 
			
		||||
} dds_entity_kind_t;
 | 
			
		||||
 | 
			
		||||
/* Handles are opaque pointers to implementation types */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,8 +13,7 @@
 | 
			
		|||
#define _DDS_RHC_H_
 | 
			
		||||
 | 
			
		||||
#include "dds/ddsrt/static_assert.h"
 | 
			
		||||
#include "dds/ddsi/q_rhc.h"
 | 
			
		||||
#include "dds__types.h" /* for dds_readcond */
 | 
			
		||||
#include "dds/ddsi/ddsi_rhc.h"
 | 
			
		||||
 | 
			
		||||
#define NO_STATE_MASK_SET   (DDS_ANY_STATE + 1)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -23,42 +22,50 @@ extern "C" {
 | 
			
		|||
#endif
 | 
			
		||||
 | 
			
		||||
struct dds_rhc;
 | 
			
		||||
struct dds_readcond;
 | 
			
		||||
struct dds_reader;
 | 
			
		||||
struct ddsi_tkmap;
 | 
			
		||||
 | 
			
		||||
typedef dds_return_t (*dds_rhc_associate_t) (struct dds_rhc *rhc, struct dds_reader *reader, const struct ddsi_sertopic *topic, struct ddsi_tkmap *tkmap);
 | 
			
		||||
typedef int (*dds_rhc_read_t) (struct dds_rhc *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, struct dds_readcond *cond);
 | 
			
		||||
typedef int (*dds_rhc_take_t) (struct dds_rhc *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, struct dds_readcond *cond);
 | 
			
		||||
typedef int (*dds_rhc_takecdr_t) (struct dds_rhc *rhc, bool lock, struct ddsi_serdata **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t sample_states, uint32_t view_states, uint32_t instance_states, dds_instance_handle_t handle);
 | 
			
		||||
 | 
			
		||||
typedef bool (*dds_rhc_add_readcondition_t) (struct dds_readcond *cond);
 | 
			
		||||
typedef void (*dds_rhc_remove_readcondition_t) (struct dds_readcond *cond);
 | 
			
		||||
typedef bool (*dds_rhc_add_readcondition_t) (struct dds_rhc *rhc, struct dds_readcond *cond);
 | 
			
		||||
typedef void (*dds_rhc_remove_readcondition_t) (struct dds_rhc *rhc, struct dds_readcond *cond);
 | 
			
		||||
 | 
			
		||||
typedef uint32_t (*dds_rhc_lock_samples_t) (struct dds_rhc *rhc);
 | 
			
		||||
 | 
			
		||||
struct dds_rhc_ops {
 | 
			
		||||
  /* A copy of DDSI rhc ops comes first so we can use either interface without
 | 
			
		||||
     additional indirections */
 | 
			
		||||
  struct rhc_ops rhc_ops;
 | 
			
		||||
  struct ddsi_rhc_ops rhc_ops;
 | 
			
		||||
  dds_rhc_read_t read;
 | 
			
		||||
  dds_rhc_take_t take;
 | 
			
		||||
  dds_rhc_takecdr_t takecdr;
 | 
			
		||||
  dds_rhc_add_readcondition_t add_readcondition;
 | 
			
		||||
  dds_rhc_remove_readcondition_t remove_readcondition;
 | 
			
		||||
  dds_rhc_lock_samples_t lock_samples;
 | 
			
		||||
  dds_rhc_associate_t associate;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct dds_rhc {
 | 
			
		||||
  union {
 | 
			
		||||
    const struct dds_rhc_ops *ops;
 | 
			
		||||
    struct rhc rhc;
 | 
			
		||||
    struct ddsi_rhc rhc;
 | 
			
		||||
  } common;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
DDSRT_STATIC_ASSERT (offsetof (struct dds_rhc, common.ops) == offsetof (struct rhc, ops));
 | 
			
		||||
DDSRT_STATIC_ASSERT (offsetof (struct dds_rhc, common.ops) == offsetof (struct ddsi_rhc, ops));
 | 
			
		||||
 | 
			
		||||
DDS_EXPORT inline bool dds_rhc_store (struct dds_rhc * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info, struct ddsi_serdata * __restrict sample, struct ddsi_tkmap_instance * __restrict tk) {
 | 
			
		||||
  return rhc->common.ops->rhc_ops.store (&rhc->common.rhc, pwr_info, sample, tk);
 | 
			
		||||
DDS_EXPORT inline dds_return_t dds_rhc_associate (struct dds_rhc *rhc, struct dds_reader *reader, const struct ddsi_sertopic *topic, struct ddsi_tkmap *tkmap) {
 | 
			
		||||
  return rhc->common.ops->associate (rhc, reader, topic, tkmap);
 | 
			
		||||
}
 | 
			
		||||
DDS_EXPORT inline void dds_rhc_unregister_wr (struct dds_rhc * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info) {
 | 
			
		||||
  rhc->common.ops->rhc_ops.unregister_wr (&rhc->common.rhc, pwr_info);
 | 
			
		||||
DDS_EXPORT inline bool dds_rhc_store (struct dds_rhc * __restrict rhc, const struct ddsi_writer_info * __restrict wrinfo, struct ddsi_serdata * __restrict sample, struct ddsi_tkmap_instance * __restrict tk) {
 | 
			
		||||
  return rhc->common.ops->rhc_ops.store (&rhc->common.rhc, wrinfo, sample, tk);
 | 
			
		||||
}
 | 
			
		||||
DDS_EXPORT inline void dds_rhc_unregister_wr (struct dds_rhc * __restrict rhc, const struct ddsi_writer_info * __restrict wrinfo) {
 | 
			
		||||
  rhc->common.ops->rhc_ops.unregister_wr (&rhc->common.rhc, wrinfo);
 | 
			
		||||
}
 | 
			
		||||
DDS_EXPORT inline void dds_rhc_relinquish_ownership (struct dds_rhc * __restrict rhc, const uint64_t wr_iid) {
 | 
			
		||||
  rhc->common.ops->rhc_ops.relinquish_ownership (&rhc->common.rhc, wr_iid);
 | 
			
		||||
| 
						 | 
				
			
			@ -78,16 +85,18 @@ DDS_EXPORT inline int dds_rhc_take (struct dds_rhc *rhc, bool lock, void **value
 | 
			
		|||
DDS_EXPORT inline int dds_rhc_takecdr (struct dds_rhc *rhc, bool lock, struct ddsi_serdata **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t sample_states, uint32_t view_states, uint32_t instance_states, dds_instance_handle_t handle) {
 | 
			
		||||
  return rhc->common.ops->takecdr (rhc, lock, values, info_seq, max_samples, sample_states, view_states, instance_states, handle);
 | 
			
		||||
}
 | 
			
		||||
DDS_EXPORT inline bool dds_rhc_add_readcondition (struct dds_readcond *cond) {
 | 
			
		||||
  return cond->m_rhc->common.ops->add_readcondition (cond);
 | 
			
		||||
DDS_EXPORT inline bool dds_rhc_add_readcondition (struct dds_rhc *rhc, struct dds_readcond *cond) {
 | 
			
		||||
  return rhc->common.ops->add_readcondition (rhc, cond);
 | 
			
		||||
}
 | 
			
		||||
DDS_EXPORT inline void dds_rhc_remove_readcondition (struct dds_readcond *cond) {
 | 
			
		||||
  cond->m_rhc->common.ops->remove_readcondition (cond);
 | 
			
		||||
DDS_EXPORT inline void dds_rhc_remove_readcondition (struct dds_rhc *rhc, struct dds_readcond *cond) {
 | 
			
		||||
  rhc->common.ops->remove_readcondition (rhc, cond);
 | 
			
		||||
}
 | 
			
		||||
DDS_EXPORT inline uint32_t dds_rhc_lock_samples (struct dds_rhc *rhc) {
 | 
			
		||||
  return rhc->common.ops->lock_samples (rhc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DDS_EXPORT void dds_reader_data_available_cb (struct dds_reader *rd);
 | 
			
		||||
 | 
			
		||||
#if defined (__cplusplus)
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -18,8 +18,7 @@
 | 
			
		|||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
DDS_EXPORT dds_return_t dds_domain_create (dds_domain **domain_out, dds_domainid_t id);
 | 
			
		||||
DDS_EXPORT void dds_domain_free (dds_domain *domain);
 | 
			
		||||
DDS_EXPORT dds_return_t dds_domain_create_internal (dds_domain **domain_out, dds_domainid_t id, bool use_existing, const char *config) ddsrt_nonnull((1,4));
 | 
			
		||||
DDS_EXPORT dds_domain *dds_domain_find_locked (dds_domainid_t id);
 | 
			
		||||
 | 
			
		||||
#if defined (__cplusplus)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,6 +28,8 @@ dds_entity_init(
 | 
			
		|||
  const dds_listener_t *listener,
 | 
			
		||||
  status_mask_t mask);
 | 
			
		||||
 | 
			
		||||
DDS_EXPORT void dds_entity_init_complete (dds_entity *entity);
 | 
			
		||||
 | 
			
		||||
DDS_EXPORT void
 | 
			
		||||
dds_entity_register_child (
 | 
			
		||||
  dds_entity *parent,
 | 
			
		||||
| 
						 | 
				
			
			@ -46,7 +48,6 @@ dds_entity_add_ref_locked(dds_entity *e);
 | 
			
		|||
    *x = (type_ *) e; \
 | 
			
		||||
    return DDS_RETCODE_OK; \
 | 
			
		||||
  } \
 | 
			
		||||
  \
 | 
			
		||||
  qualifier_ void type_##_unlock (type_ *x) \
 | 
			
		||||
  { \
 | 
			
		||||
    dds_entity_unlock (&x->m_entity); \
 | 
			
		||||
| 
						 | 
				
			
			@ -78,6 +79,18 @@ DDS_EXPORT void dds_entity_status_signal (dds_entity *e, uint32_t status);
 | 
			
		|||
 | 
			
		||||
DDS_EXPORT void dds_entity_invoke_listener (const dds_entity *entity, enum dds_status_id which, const void *vst);
 | 
			
		||||
 | 
			
		||||
DDS_EXPORT dds_participant *dds_entity_participant (dds_entity *e);
 | 
			
		||||
DDS_EXPORT void dds_entity_final_deinit_before_free (dds_entity *e);
 | 
			
		||||
DDS_EXPORT bool dds_entity_in_scope (const dds_entity *e, const dds_entity *root);
 | 
			
		||||
 | 
			
		||||
enum delete_impl_state {
 | 
			
		||||
  DIS_EXPLICIT,    /* explicit delete on this entity */
 | 
			
		||||
  DIS_FROM_PARENT, /* called because the parent is being deleted */
 | 
			
		||||
  DIS_IMPLICIT     /* called from child; delete if implicit w/o children */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
DDS_EXPORT dds_return_t dds_delete_impl_pinned (dds_entity *e, enum delete_impl_state delstate);
 | 
			
		||||
 | 
			
		||||
DDS_EXPORT dds_return_t
 | 
			
		||||
dds_entity_pin (
 | 
			
		||||
  dds_entity_t hdl,
 | 
			
		||||
| 
						 | 
				
			
			@ -98,23 +111,16 @@ dds_entity_unlock(dds_entity *e);
 | 
			
		|||
DDS_EXPORT dds_return_t
 | 
			
		||||
dds_entity_observer_register(
 | 
			
		||||
  dds_entity *observed,
 | 
			
		||||
  dds_entity *observer,
 | 
			
		||||
  dds_entity_callback cb,
 | 
			
		||||
  dds_entity_delete_callback delete_cb);
 | 
			
		||||
  dds_waitset *observer,
 | 
			
		||||
  dds_entity_callback_t cb,
 | 
			
		||||
  dds_entity_attach_callback_t attach_cb, void *attach_arg,
 | 
			
		||||
  dds_entity_delete_callback_t delete_cb);
 | 
			
		||||
 | 
			
		||||
DDS_EXPORT dds_return_t
 | 
			
		||||
dds_entity_observer_unregister(
 | 
			
		||||
  dds_entity *observed,
 | 
			
		||||
  dds_entity *observer);
 | 
			
		||||
 | 
			
		||||
DDS_EXPORT dds_return_t
 | 
			
		||||
dds_delete_impl(
 | 
			
		||||
  dds_entity_t entity,
 | 
			
		||||
  bool keep_if_explicit);
 | 
			
		||||
 | 
			
		||||
DDS_EXPORT dds_domain *
 | 
			
		||||
dds__entity_domain(
 | 
			
		||||
  dds_entity* e);
 | 
			
		||||
  dds_waitset *observer,
 | 
			
		||||
  bool invoke_delete_cb);
 | 
			
		||||
 | 
			
		||||
DDS_EXPORT dds_return_t
 | 
			
		||||
dds_generic_unimplemented_operation_manykinds(
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -69,6 +69,13 @@ typedef int32_t dds_handle_t;
 | 
			
		|||
 * This handlelink is invalid after the related handle is deleted and should
 | 
			
		||||
 * never be used afterwards.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* Closing & closed can be combined, but having two gives a means for enforcing
 | 
			
		||||
   that close() be called first, then close_wait(), and then delete(). */
 | 
			
		||||
#define HDL_FLAG_CLOSING   (0x80000000u)
 | 
			
		||||
#define HDL_FLAG_CLOSED    (0x40000000u)
 | 
			
		||||
#define HDL_FLAG_PENDING   (0x20000000u)
 | 
			
		||||
 | 
			
		||||
struct dds_handle_link {
 | 
			
		||||
  dds_handle_t hdl;
 | 
			
		||||
  ddsrt_atomic_uint32_t cnt_flags;
 | 
			
		||||
| 
						 | 
				
			
			@ -112,6 +119,15 @@ dds_handle_create(
 | 
			
		|||
        struct dds_handle_link *link);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Register a specific handle.
 | 
			
		||||
 */
 | 
			
		||||
DDS_EXPORT dds_return_t
 | 
			
		||||
dds_handle_register_special (
 | 
			
		||||
        struct dds_handle_link *link, dds_handle_t handle);
 | 
			
		||||
 | 
			
		||||
DDS_EXPORT void dds_handle_unpend (struct dds_handle_link *link);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * This will close the handle. All information remains, only new claims will
 | 
			
		||||
 * fail.
 | 
			
		||||
| 
						 | 
				
			
			@ -119,10 +135,9 @@ dds_handle_create(
 | 
			
		|||
 * This is a noop on an already closed handle.
 | 
			
		||||
 */
 | 
			
		||||
DDS_EXPORT void
 | 
			
		||||
dds_handle_close(
 | 
			
		||||
dds_handle_close_wait (
 | 
			
		||||
        struct dds_handle_link *link);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * This will remove the handle related information from the server administration
 | 
			
		||||
 * to free up space.
 | 
			
		||||
| 
						 | 
				
			
			@ -134,8 +149,7 @@ dds_handle_close(
 | 
			
		|||
 */
 | 
			
		||||
DDS_EXPORT int32_t
 | 
			
		||||
dds_handle_delete(
 | 
			
		||||
        struct dds_handle_link *link,
 | 
			
		||||
        dds_time_t timeout);
 | 
			
		||||
        struct dds_handle_link *link);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
| 
						 | 
				
			
			@ -149,6 +163,11 @@ dds_handle_pin(
 | 
			
		|||
        dds_handle_t hdl,
 | 
			
		||||
        struct dds_handle_link **entity);
 | 
			
		||||
 | 
			
		||||
DDS_EXPORT int32_t
 | 
			
		||||
dds_handle_pin_and_ref(
 | 
			
		||||
        dds_handle_t hdl,
 | 
			
		||||
        struct dds_handle_link **entity);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
DDS_EXPORT void
 | 
			
		||||
dds_handle_repin(
 | 
			
		||||
| 
						 | 
				
			
			@ -172,14 +191,15 @@ dds_handle_unpin(
 | 
			
		|||
 * break of your process and release the handle, making the deletion
 | 
			
		||||
 * possible.
 | 
			
		||||
 */
 | 
			
		||||
DDS_EXPORT bool
 | 
			
		||||
dds_handle_is_closed(
 | 
			
		||||
        struct dds_handle_link *link);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
DDS_EXPORT void dds_handle_add_ref (struct dds_handle_link *link);
 | 
			
		||||
DDS_EXPORT bool dds_handle_drop_ref (struct dds_handle_link *link);
 | 
			
		||||
 | 
			
		||||
DDS_EXPORT inline bool dds_handle_is_closed (struct dds_handle_link *link) {
 | 
			
		||||
  return (ddsrt_atomic_ld32 (&link->cnt_flags) & (HDL_FLAG_CLOSED | HDL_FLAG_CLOSING)) != 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if defined (__cplusplus)
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,27 +19,15 @@ extern "C" {
 | 
			
		|||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *Description : Initialization function, called from main. This operation
 | 
			
		||||
 *initializes all the required DDS resources,
 | 
			
		||||
 *handles configuration of domainid based on the input passed, parses and
 | 
			
		||||
 *configures middleware from a xml file and initializes required resources.
 | 
			
		||||
 *Description : Initializes the library and constructs the global
 | 
			
		||||
 *pseudo-entity identified by DDS_CYCLONEDDS_HANDLE with one reference
 | 
			
		||||
 *that must (eventually) be released by calling dds_delete on that handle.
 | 
			
		||||
 *
 | 
			
		||||
 *Arguments :
 | 
			
		||||
 *-# Returns 0 on success or a non-zero error status
 | 
			
		||||
 **/
 | 
			
		||||
dds_return_t dds_init (void);
 | 
			
		||||
 | 
			
		||||
/* Finalization function, called from main */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *Description : Finalization function, called from main. This operation
 | 
			
		||||
 *releases all the resources used by DDS.
 | 
			
		||||
 *
 | 
			
		||||
 *Arguments :
 | 
			
		||||
 *-# None
 | 
			
		||||
 **/
 | 
			
		||||
void dds_fini (void);
 | 
			
		||||
 | 
			
		||||
#if defined (__cplusplus)
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,8 +23,6 @@ struct status_cb_data;
 | 
			
		|||
 | 
			
		||||
void dds_reader_status_cb (void *entity, const struct status_cb_data * data);
 | 
			
		||||
 | 
			
		||||
void dds_reader_data_available_cb (struct dds_reader *entity);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
  dds_reader_lock_samples: Returns number of samples in read cache and locks the
 | 
			
		||||
  reader cache to make sure that the samples content doesn't change.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,7 +22,7 @@ extern "C" {
 | 
			
		|||
 | 
			
		||||
struct ddsi_serdata_builtintopic {
 | 
			
		||||
  struct ddsi_serdata c;
 | 
			
		||||
  nn_guid_t key;
 | 
			
		||||
  ddsi_guid_t key;
 | 
			
		||||
  dds_instance_handle_t pphandle;
 | 
			
		||||
  dds_qos_t xqos;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -60,6 +60,10 @@ void dds_stream_extract_keyhash (dds_istream_t * __restrict is, dds_keyhash_t *
 | 
			
		|||
 | 
			
		||||
void dds_stream_read_key (dds_istream_t * __restrict is, char * __restrict sample, const struct ddsi_sertopic_default * __restrict topic);
 | 
			
		||||
 | 
			
		||||
size_t dds_stream_print_key (dds_istream_t * __restrict is, const struct ddsi_sertopic_default * __restrict topic, char * __restrict buf, size_t size);
 | 
			
		||||
 | 
			
		||||
size_t dds_stream_print_sample (dds_istream_t * __restrict is, const struct ddsi_sertopic_default * __restrict topic, char * __restrict buf, size_t size);
 | 
			
		||||
 | 
			
		||||
/* For marshalling op code handling */
 | 
			
		||||
 | 
			
		||||
#define DDS_OP_MASK 0xff000000
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -39,7 +39,7 @@ struct dds_guardcond;
 | 
			
		|||
struct dds_statuscond;
 | 
			
		||||
 | 
			
		||||
struct ddsi_sertopic;
 | 
			
		||||
struct rhc;
 | 
			
		||||
struct ddsi_rhc;
 | 
			
		||||
 | 
			
		||||
typedef uint16_t status_mask_t;
 | 
			
		||||
typedef ddsrt_atomic_uint32_t status_and_enabled_t;
 | 
			
		||||
| 
						 | 
				
			
			@ -90,47 +90,32 @@ struct dds_listener {
 | 
			
		|||
 | 
			
		||||
/* Entity flag values */
 | 
			
		||||
 | 
			
		||||
#define DDS_ENTITY_ENABLED      0x0001u
 | 
			
		||||
#define DDS_ENTITY_IMPLICIT     0x0002u
 | 
			
		||||
 | 
			
		||||
typedef struct dds_domain {
 | 
			
		||||
  /* FIXME: protected by dds_global.lock -- for now */
 | 
			
		||||
  ddsrt_avl_node_t m_node;
 | 
			
		||||
  dds_domainid_t m_id;
 | 
			
		||||
  ddsrt_avl_tree_t m_topics;
 | 
			
		||||
  ddsrt_avl_tree_t m_ppants;
 | 
			
		||||
  uint32_t m_refc;
 | 
			
		||||
  struct cfgst *cfgst;
 | 
			
		||||
 | 
			
		||||
  struct ddsi_sertopic *builtin_participant_topic;
 | 
			
		||||
  struct ddsi_sertopic *builtin_reader_topic;
 | 
			
		||||
  struct ddsi_sertopic *builtin_writer_topic;
 | 
			
		||||
 | 
			
		||||
  struct local_orphan_writer *builtintopic_writer_participant;
 | 
			
		||||
  struct local_orphan_writer *builtintopic_writer_publications;
 | 
			
		||||
  struct local_orphan_writer *builtintopic_writer_subscriptions;
 | 
			
		||||
 | 
			
		||||
  struct ddsi_builtin_topic_interface btif;
 | 
			
		||||
  struct q_globals gv;
 | 
			
		||||
} dds_domain;
 | 
			
		||||
#define DDS_ENTITY_ENABLED      ((uint32_t) 0x1) /* DDS "enabled" state */
 | 
			
		||||
#define DDS_ENTITY_IMPLICIT     ((uint32_t) 0x2) /* implicit ones get deleted when the last child is deleted */
 | 
			
		||||
 | 
			
		||||
struct dds_domain;
 | 
			
		||||
struct dds_entity;
 | 
			
		||||
 | 
			
		||||
typedef struct dds_entity_deriver {
 | 
			
		||||
  /* Close can be used to terminate (blocking) actions on a entity before actually deleting it. */
 | 
			
		||||
  dds_return_t (*close)(struct dds_entity *e) ddsrt_nonnull_all;
 | 
			
		||||
  /* Pending close can be used to terminate (blocking) actions on a entity before actually deleting it. */
 | 
			
		||||
  void (*interrupt) (struct dds_entity *e) ddsrt_nonnull_all;
 | 
			
		||||
  /* Close can be used to do ... */
 | 
			
		||||
  void (*close) (struct dds_entity *e) ddsrt_nonnull_all;
 | 
			
		||||
  /* Delete is used to actually free the entity. */
 | 
			
		||||
  dds_return_t (*delete)(struct dds_entity *e) ddsrt_nonnull_all;
 | 
			
		||||
  dds_return_t (*set_qos)(struct dds_entity *e, const dds_qos_t *qos, bool enabled) ddsrt_nonnull_all;
 | 
			
		||||
  dds_return_t (*validate_status)(uint32_t mask);
 | 
			
		||||
  dds_return_t (*delete) (struct dds_entity *e) ddsrt_nonnull_all;
 | 
			
		||||
  dds_return_t (*set_qos) (struct dds_entity *e, const dds_qos_t *qos, bool enabled) ddsrt_nonnull_all;
 | 
			
		||||
  dds_return_t (*validate_status) (uint32_t mask);
 | 
			
		||||
} dds_entity_deriver;
 | 
			
		||||
 | 
			
		||||
typedef void (*dds_entity_callback)(struct dds_entity *observer, dds_entity_t observed, uint32_t status);
 | 
			
		||||
typedef void (*dds_entity_delete_callback)(struct dds_entity *observer, dds_entity_t observed);
 | 
			
		||||
struct dds_waitset;
 | 
			
		||||
typedef void (*dds_entity_callback_t) (struct dds_waitset *observer, dds_entity_t observed, uint32_t status);
 | 
			
		||||
typedef bool (*dds_entity_attach_callback_t) (struct dds_waitset *observer, struct dds_entity *observed, void *attach_arg);
 | 
			
		||||
typedef void (*dds_entity_delete_callback_t) (struct dds_waitset *observer, dds_entity_t observed);
 | 
			
		||||
 | 
			
		||||
typedef struct dds_entity_observer {
 | 
			
		||||
  dds_entity_callback m_cb;
 | 
			
		||||
  dds_entity_delete_callback m_delete_cb;
 | 
			
		||||
  struct dds_entity *m_observer;
 | 
			
		||||
  dds_entity_callback_t m_cb;
 | 
			
		||||
  dds_entity_delete_callback_t m_delete_cb;
 | 
			
		||||
  struct dds_waitset *m_observer;
 | 
			
		||||
  struct dds_entity_observer *m_next;
 | 
			
		||||
} dds_entity_observer;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -141,10 +126,9 @@ typedef struct dds_entity {
 | 
			
		|||
  struct dds_entity *m_parent;      /* constant */
 | 
			
		||||
  ddsrt_avl_node_t m_avlnode_child; /* [m_mutex of m_parent] */
 | 
			
		||||
  ddsrt_avl_tree_t m_children;      /* [m_mutex] tree on m_iid using m_avlnode_child */
 | 
			
		||||
  struct dds_entity *m_participant; /* constant */
 | 
			
		||||
  struct dds_domain *m_domain;      /* constant */
 | 
			
		||||
  dds_qos_t *m_qos;                 /* [m_mutex] */
 | 
			
		||||
  nn_guid_t m_guid;                 /* unique (if not 0) and constant; FIXME: set during creation, but possibly after becoming visible */
 | 
			
		||||
  ddsi_guid_t m_guid;               /* unique (if not 0) and constant; FIXME: set during creation, but possibly after becoming visible */
 | 
			
		||||
  dds_instance_handle_t m_iid;      /* unique for all time, constant; FIXME: like GUID */
 | 
			
		||||
  uint32_t m_flags;                 /* [m_mutex] */
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -154,6 +138,7 @@ typedef struct dds_entity {
 | 
			
		|||
       (no hierarchical relationship there)
 | 
			
		||||
     - locking topic::m_mutex while holding {reader,writer}::m_mutex
 | 
			
		||||
     - locking observers_lock while holding m_mutex
 | 
			
		||||
     - locking waitset::wait_lock
 | 
			
		||||
   */
 | 
			
		||||
  ddsrt_mutex_t m_mutex;
 | 
			
		||||
  ddsrt_cond_t m_cond;
 | 
			
		||||
| 
						 | 
				
			
			@ -167,6 +152,7 @@ typedef struct dds_entity {
 | 
			
		|||
  ddsrt_cond_t m_observers_cond;
 | 
			
		||||
  dds_listener_t m_listener;        /* [m_observers_lock] */
 | 
			
		||||
  uint32_t m_cb_count;              /* [m_observers_lock] */
 | 
			
		||||
  uint32_t m_cb_pending_count;      /* [m_observers_lock] */
 | 
			
		||||
  dds_entity_observer *m_observers; /* [m_observers_lock] */
 | 
			
		||||
} dds_entity;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -182,16 +168,21 @@ extern const struct dds_entity_deriver dds_entity_deriver_publisher;
 | 
			
		|||
extern const struct dds_entity_deriver dds_entity_deriver_readcondition;
 | 
			
		||||
extern const struct dds_entity_deriver dds_entity_deriver_guardcondition;
 | 
			
		||||
extern const struct dds_entity_deriver dds_entity_deriver_waitset;
 | 
			
		||||
extern const struct dds_entity_deriver dds_entity_deriver_domain;
 | 
			
		||||
extern const struct dds_entity_deriver dds_entity_deriver_cyclonedds;
 | 
			
		||||
extern const struct dds_entity_deriver *dds_entity_deriver_table[];
 | 
			
		||||
 | 
			
		||||
dds_return_t dds_entity_deriver_dummy_close (struct dds_entity *e);
 | 
			
		||||
void dds_entity_deriver_dummy_interrupt (struct dds_entity *e);
 | 
			
		||||
void dds_entity_deriver_dummy_close (struct dds_entity *e);
 | 
			
		||||
dds_return_t dds_entity_deriver_dummy_delete (struct dds_entity *e);
 | 
			
		||||
dds_return_t dds_entity_deriver_dummy_set_qos (struct dds_entity *e, const dds_qos_t *qos, bool enabled);
 | 
			
		||||
dds_return_t dds_entity_deriver_dummy_validate_status (uint32_t mask);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
inline dds_return_t dds_entity_deriver_close (struct dds_entity *e) {
 | 
			
		||||
  return (dds_entity_deriver_table[e->m_kind]->close) (e);
 | 
			
		||||
inline void dds_entity_deriver_interrupt (struct dds_entity *e) {
 | 
			
		||||
  (dds_entity_deriver_table[e->m_kind]->interrupt) (e);
 | 
			
		||||
}
 | 
			
		||||
inline void dds_entity_deriver_close (struct dds_entity *e) {
 | 
			
		||||
  (dds_entity_deriver_table[e->m_kind]->close) (e);
 | 
			
		||||
}
 | 
			
		||||
inline dds_return_t dds_entity_deriver_delete (struct dds_entity *e) {
 | 
			
		||||
  return dds_entity_deriver_table[e->m_kind]->delete (e);
 | 
			
		||||
| 
						 | 
				
			
			@ -209,6 +200,36 @@ inline bool dds_entity_supports_validate_status (struct dds_entity *e) {
 | 
			
		|||
  return dds_entity_deriver_table[e->m_kind]->validate_status != dds_entity_deriver_dummy_validate_status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
typedef struct dds_cyclonedds_entity {
 | 
			
		||||
  struct dds_entity m_entity;
 | 
			
		||||
 | 
			
		||||
  ddsrt_mutex_t m_mutex;
 | 
			
		||||
  ddsrt_cond_t m_cond;
 | 
			
		||||
  ddsrt_avl_tree_t m_domains;
 | 
			
		||||
  uint32_t threadmon_count;
 | 
			
		||||
  struct ddsi_threadmon *threadmon;
 | 
			
		||||
} dds_cyclonedds_entity;
 | 
			
		||||
 | 
			
		||||
typedef struct dds_domain {
 | 
			
		||||
  struct dds_entity m_entity;
 | 
			
		||||
 | 
			
		||||
  ddsrt_avl_node_t m_node; /* for dds_global.m_domains */
 | 
			
		||||
  dds_domainid_t m_id;
 | 
			
		||||
  ddsrt_avl_tree_t m_topics;
 | 
			
		||||
  struct cfgst *cfgst;
 | 
			
		||||
 | 
			
		||||
  struct ddsi_sertopic *builtin_participant_topic;
 | 
			
		||||
  struct ddsi_sertopic *builtin_reader_topic;
 | 
			
		||||
  struct ddsi_sertopic *builtin_writer_topic;
 | 
			
		||||
 | 
			
		||||
  struct local_orphan_writer *builtintopic_writer_participant;
 | 
			
		||||
  struct local_orphan_writer *builtintopic_writer_publications;
 | 
			
		||||
  struct local_orphan_writer *builtintopic_writer_subscriptions;
 | 
			
		||||
 | 
			
		||||
  struct ddsi_builtin_topic_interface btif;
 | 
			
		||||
  struct q_globals gv;
 | 
			
		||||
} dds_domain;
 | 
			
		||||
 | 
			
		||||
typedef struct dds_subscriber {
 | 
			
		||||
  struct dds_entity m_entity;
 | 
			
		||||
} dds_subscriber;
 | 
			
		||||
| 
						 | 
				
			
			@ -279,12 +300,10 @@ typedef uint32_t dds_querycond_mask_t;
 | 
			
		|||
 | 
			
		||||
typedef struct dds_readcond {
 | 
			
		||||
  dds_entity m_entity;
 | 
			
		||||
  struct dds_rhc *m_rhc;
 | 
			
		||||
  uint32_t m_qminv;
 | 
			
		||||
  uint32_t m_sample_states;
 | 
			
		||||
  uint32_t m_view_states;
 | 
			
		||||
  uint32_t m_instance_states;
 | 
			
		||||
  nn_guid_t m_rd_guid;
 | 
			
		||||
  struct dds_readcond *m_next;
 | 
			
		||||
  struct {
 | 
			
		||||
    dds_querycondition_filter_fn m_filter;
 | 
			
		||||
| 
						 | 
				
			
			@ -304,22 +323,18 @@ typedef struct dds_attachment {
 | 
			
		|||
 | 
			
		||||
typedef struct dds_waitset {
 | 
			
		||||
  dds_entity m_entity;
 | 
			
		||||
  size_t nentities;         /* [m_entity.m_mutex] */
 | 
			
		||||
  size_t ntriggered;        /* [m_entity.m_mutex] */
 | 
			
		||||
  dds_attachment *entities; /* [m_entity.m_mutex] 0 .. ntriggered are triggred, ntriggred .. nentities are not */
 | 
			
		||||
 | 
			
		||||
  /* Need a lock other than m_entity.m_mutex because the locking order an entity lock may not be
 | 
			
		||||
     acquired while holding an ancestor's lock, but a waitset must be capable of triggering on
 | 
			
		||||
     events on its parent */
 | 
			
		||||
  ddsrt_mutex_t wait_lock;
 | 
			
		||||
  ddsrt_cond_t wait_cond;
 | 
			
		||||
  size_t nentities;         /* [wait_lock] */
 | 
			
		||||
  size_t ntriggered;        /* [wait_lock] */
 | 
			
		||||
  dds_attachment *entities; /* [wait_lock] 0 .. ntriggered are triggred, ntriggred .. nentities are not */
 | 
			
		||||
} dds_waitset;
 | 
			
		||||
 | 
			
		||||
/* Globals */
 | 
			
		||||
 | 
			
		||||
typedef struct dds_globals {
 | 
			
		||||
  int32_t m_init_count;
 | 
			
		||||
  ddsrt_avl_tree_t m_domains;
 | 
			
		||||
  ddsrt_mutex_t m_mutex;
 | 
			
		||||
  uint32_t threadmon_count;
 | 
			
		||||
  struct ddsi_threadmon *threadmon;
 | 
			
		||||
} dds_globals;
 | 
			
		||||
 | 
			
		||||
DDS_EXPORT extern dds_globals dds_global;
 | 
			
		||||
DDS_EXPORT extern dds_cyclonedds_entity dds_global;
 | 
			
		||||
 | 
			
		||||
#if defined (__cplusplus)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,6 +22,7 @@
 | 
			
		|||
#include "dds__participant.h"
 | 
			
		||||
#include "dds__types.h"
 | 
			
		||||
#include "dds__builtin.h"
 | 
			
		||||
#include "dds__entity.h"
 | 
			
		||||
#include "dds__subscriber.h"
 | 
			
		||||
#include "dds__write.h"
 | 
			
		||||
#include "dds__writer.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -46,9 +47,15 @@ dds_entity_t dds__get_builtin_topic (dds_entity_t entity, dds_entity_t topic)
 | 
			
		|||
  dds_entity_t tp;
 | 
			
		||||
  dds_return_t rc;
 | 
			
		||||
  dds_entity *e;
 | 
			
		||||
  dds_participant *par;
 | 
			
		||||
 | 
			
		||||
  if ((rc = dds_entity_pin (entity, &e)) < 0)
 | 
			
		||||
    return rc;
 | 
			
		||||
  if ((par = dds_entity_participant (e)) == NULL)
 | 
			
		||||
  {
 | 
			
		||||
    dds_entity_unpin (e);
 | 
			
		||||
    return DDS_RETCODE_ILLEGAL_OPERATION;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  struct ddsi_sertopic *sertopic;
 | 
			
		||||
  switch (topic)
 | 
			
		||||
| 
						 | 
				
			
			@ -69,7 +76,7 @@ dds_entity_t dds__get_builtin_topic (dds_entity_t entity, dds_entity_t topic)
 | 
			
		|||
  }
 | 
			
		||||
 | 
			
		||||
  dds_qos_t *qos = dds__create_builtin_qos ();
 | 
			
		||||
  tp = dds_create_topic_arbitrary (e->m_participant->m_hdllink.hdl, sertopic, qos, NULL, NULL);
 | 
			
		||||
  tp = dds_create_topic_arbitrary (par->m_entity.m_hdllink.hdl, sertopic, qos, NULL, NULL);
 | 
			
		||||
  dds_delete_qos (qos);
 | 
			
		||||
  dds_entity_unpin (e);
 | 
			
		||||
  return tp;
 | 
			
		||||
| 
						 | 
				
			
			@ -155,7 +162,7 @@ static bool dds__builtin_is_builtintopic (const struct ddsi_sertopic *tp, void *
 | 
			
		|||
  return tp->ops == &ddsi_sertopic_ops_builtintopic;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool dds__builtin_is_visible (const nn_guid_t *guid, nn_vendorid_t vendorid, void *vdomain)
 | 
			
		||||
static bool dds__builtin_is_visible (const ddsi_guid_t *guid, nn_vendorid_t vendorid, void *vdomain)
 | 
			
		||||
{
 | 
			
		||||
  (void) vdomain;
 | 
			
		||||
  if (is_builtin_endpoint (guid->entityid, vendorid))
 | 
			
		||||
| 
						 | 
				
			
			@ -163,7 +170,7 @@ static bool dds__builtin_is_visible (const nn_guid_t *guid, nn_vendorid_t vendor
 | 
			
		|||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct ddsi_tkmap_instance *dds__builtin_get_tkmap_entry (const struct nn_guid *guid, void *vdomain)
 | 
			
		||||
static struct ddsi_tkmap_instance *dds__builtin_get_tkmap_entry (const struct ddsi_guid *guid, void *vdomain)
 | 
			
		||||
{
 | 
			
		||||
  struct dds_domain *domain = vdomain;
 | 
			
		||||
  struct ddsi_tkmap_instance *tk;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,14 +11,14 @@
 | 
			
		|||
 */
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#include "dds/ddsrt/environ.h"
 | 
			
		||||
#include "dds/ddsrt/process.h"
 | 
			
		||||
#include "dds/ddsrt/heap.h"
 | 
			
		||||
#include "dds__init.h"
 | 
			
		||||
#include "dds__rhc.h"
 | 
			
		||||
#include "dds/ddsc/dds_rhc.h"
 | 
			
		||||
#include "dds__domain.h"
 | 
			
		||||
#include "dds__builtin.h"
 | 
			
		||||
#include "dds__whc_builtintopic.h"
 | 
			
		||||
#include "dds__entity.h"
 | 
			
		||||
#include "dds/ddsi/ddsi_iid.h"
 | 
			
		||||
#include "dds/ddsi/ddsi_tkmap.h"
 | 
			
		||||
#include "dds/ddsi/ddsi_serdata.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -27,7 +27,16 @@
 | 
			
		|||
#include "dds/ddsi/q_config.h"
 | 
			
		||||
#include "dds/ddsi/q_gc.h"
 | 
			
		||||
#include "dds/ddsi/q_globals.h"
 | 
			
		||||
#include "dds/version.h"
 | 
			
		||||
 | 
			
		||||
static dds_return_t dds_domain_free (dds_entity *vdomain);
 | 
			
		||||
 | 
			
		||||
const struct dds_entity_deriver dds_entity_deriver_domain = {
 | 
			
		||||
  .interrupt = dds_entity_deriver_dummy_interrupt,
 | 
			
		||||
  .close = dds_entity_deriver_dummy_close,
 | 
			
		||||
  .delete = dds_domain_free,
 | 
			
		||||
  .set_qos = dds_entity_deriver_dummy_set_qos,
 | 
			
		||||
  .validate_status = dds_entity_deriver_dummy_validate_status
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int dds_domain_compare (const void *va, const void *vb)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -39,14 +48,20 @@ static int dds_domain_compare (const void *va, const void *vb)
 | 
			
		|||
static const ddsrt_avl_treedef_t dds_domaintree_def = DDSRT_AVL_TREEDEF_INITIALIZER (
 | 
			
		||||
  offsetof (dds_domain, m_node), offsetof (dds_domain, m_id), dds_domain_compare, 0);
 | 
			
		||||
 | 
			
		||||
static dds_return_t dds_domain_init (dds_domain *domain, dds_domainid_t domain_id)
 | 
			
		||||
static dds_return_t dds_domain_init (dds_domain *domain, dds_domainid_t domain_id, const char *config)
 | 
			
		||||
{
 | 
			
		||||
  dds_return_t ret = DDS_RETCODE_OK;
 | 
			
		||||
  char * uri = NULL;
 | 
			
		||||
  uint32_t len;
 | 
			
		||||
  dds_entity_t domain_handle;
 | 
			
		||||
 | 
			
		||||
  if ((domain_handle = dds_entity_init (&domain->m_entity, &dds_global.m_entity, DDS_KIND_DOMAIN, NULL, NULL, 0)) < 0)
 | 
			
		||||
    return domain_handle;
 | 
			
		||||
  domain->m_entity.m_domain = domain;
 | 
			
		||||
  domain->m_entity.m_flags |= DDS_ENTITY_IMPLICIT;
 | 
			
		||||
  domain->m_entity.m_iid = ddsi_iid_gen ();
 | 
			
		||||
 | 
			
		||||
  domain->gv.tstart = now ();
 | 
			
		||||
  domain->m_refc = 1;
 | 
			
		||||
  ddsrt_avl_init (&dds_topictree_def, &domain->m_topics);
 | 
			
		||||
 | 
			
		||||
  /* | domain_id | domain id in config | result
 | 
			
		||||
| 
						 | 
				
			
			@ -72,8 +87,7 @@ static dds_return_t dds_domain_init (dds_domain *domain, dds_domainid_t domain_i
 | 
			
		|||
        a value (if nothing has been set previously, it a warning is good
 | 
			
		||||
        enough) */
 | 
			
		||||
 | 
			
		||||
  (void) ddsrt_getenv ("CYCLONEDDS_URI", &uri);
 | 
			
		||||
  domain->cfgst = config_init (uri, &domain->gv.config, domain_id);
 | 
			
		||||
  domain->cfgst = config_init (config, &domain->gv.config, domain_id);
 | 
			
		||||
  if (domain->cfgst == NULL)
 | 
			
		||||
  {
 | 
			
		||||
    DDS_ILOG (DDS_LC_CONFIG, domain_id, "Failed to parse configuration XML file %s\n", uri);
 | 
			
		||||
| 
						 | 
				
			
			@ -152,9 +166,9 @@ static dds_return_t dds_domain_init (dds_domain *domain, dds_domainid_t domain_i
 | 
			
		|||
 | 
			
		||||
  if (domain->gv.config.liveliness_monitoring)
 | 
			
		||||
    ddsi_threadmon_register_domain (dds_global.threadmon, &domain->gv);
 | 
			
		||||
  dds_entity_init_complete (&domain->m_entity);
 | 
			
		||||
  return DDS_RETCODE_OK;
 | 
			
		||||
 | 
			
		||||
  rtps_stop (&domain->gv);
 | 
			
		||||
fail_rtps_start:
 | 
			
		||||
  if (domain->gv.config.liveliness_monitoring && dds_global.threadmon_count == 1)
 | 
			
		||||
    ddsi_threadmon_stop (dds_global.threadmon);
 | 
			
		||||
| 
						 | 
				
			
			@ -170,43 +184,23 @@ fail_rtps_init:
 | 
			
		|||
fail_rtps_config:
 | 
			
		||||
  config_fini (domain->cfgst);
 | 
			
		||||
fail_config:
 | 
			
		||||
  dds_handle_delete (&domain->m_entity.m_hdllink);
 | 
			
		||||
  return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void dds_domain_fini (struct dds_domain *domain)
 | 
			
		||||
{
 | 
			
		||||
  rtps_stop (&domain->gv);
 | 
			
		||||
  dds__builtin_fini (domain);
 | 
			
		||||
 | 
			
		||||
  if (domain->gv.config.liveliness_monitoring)
 | 
			
		||||
    ddsi_threadmon_unregister_domain (dds_global.threadmon, &domain->gv);
 | 
			
		||||
 | 
			
		||||
  rtps_fini (&domain->gv);
 | 
			
		||||
 | 
			
		||||
  ddsrt_mutex_lock (&dds_global.m_mutex);
 | 
			
		||||
  if (domain->gv.config.liveliness_monitoring && --dds_global.threadmon_count == 0)
 | 
			
		||||
  {
 | 
			
		||||
    ddsi_threadmon_stop (dds_global.threadmon);
 | 
			
		||||
    ddsi_threadmon_free (dds_global.threadmon);
 | 
			
		||||
  }
 | 
			
		||||
  ddsrt_mutex_unlock (&dds_global.m_mutex);
 | 
			
		||||
 | 
			
		||||
  config_fini (domain->cfgst);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dds_domain *dds_domain_find_locked (dds_domainid_t id)
 | 
			
		||||
{
 | 
			
		||||
  return ddsrt_avl_lookup (&dds_domaintree_def, &dds_global.m_domains, &id);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dds_return_t dds_domain_create (dds_domain **domain_out, dds_domainid_t id)
 | 
			
		||||
dds_return_t dds_domain_create_internal (dds_domain **domain_out, dds_domainid_t id, bool use_existing, const char *config)
 | 
			
		||||
{
 | 
			
		||||
  struct dds_domain *dom = NULL;
 | 
			
		||||
  struct dds_domain *dom;
 | 
			
		||||
  dds_return_t ret;
 | 
			
		||||
 | 
			
		||||
  /* FIXME: should perhaps lock parent object just like everywhere */
 | 
			
		||||
  ddsrt_mutex_lock (&dds_global.m_mutex);
 | 
			
		||||
 | 
			
		||||
  /* FIXME: hack around default domain ids, not yet being able to handle multiple domains simultaneously */
 | 
			
		||||
 retry:
 | 
			
		||||
  if (id != DDS_DOMAIN_DEFAULT)
 | 
			
		||||
  {
 | 
			
		||||
    if ((dom = dds_domain_find_locked (id)) == NULL)
 | 
			
		||||
| 
						 | 
				
			
			@ -225,41 +219,94 @@ dds_return_t dds_domain_create (dds_domain **domain_out, dds_domainid_t id)
 | 
			
		|||
  switch (ret)
 | 
			
		||||
  {
 | 
			
		||||
    case DDS_RETCODE_OK:
 | 
			
		||||
      dom->m_refc++;
 | 
			
		||||
      *domain_out = dom;
 | 
			
		||||
      break;
 | 
			
		||||
    case DDS_RETCODE_NOT_FOUND:
 | 
			
		||||
      dom = dds_alloc (sizeof (*dom));
 | 
			
		||||
      if ((ret = dds_domain_init (dom, id)) < 0)
 | 
			
		||||
        dds_free (dom);
 | 
			
		||||
      if (!use_existing)
 | 
			
		||||
      {
 | 
			
		||||
        ret = DDS_RETCODE_PRECONDITION_NOT_MET;
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      ddsrt_mutex_lock (&dom->m_entity.m_mutex);
 | 
			
		||||
      if (dds_handle_is_closed (&dom->m_entity.m_hdllink))
 | 
			
		||||
      {
 | 
			
		||||
        ddsrt_mutex_unlock (&dom->m_entity.m_mutex);
 | 
			
		||||
        ddsrt_cond_wait (&dds_global.m_cond, &dds_global.m_mutex);
 | 
			
		||||
        goto retry;
 | 
			
		||||
      }
 | 
			
		||||
      else
 | 
			
		||||
      {
 | 
			
		||||
        ddsrt_avl_insert (&dds_domaintree_def, &dds_global.m_domains, dom);
 | 
			
		||||
        dds_entity_add_ref_locked (&dom->m_entity);
 | 
			
		||||
        ddsrt_mutex_unlock (&dom->m_entity.m_mutex);
 | 
			
		||||
        *domain_out = dom;
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
    case DDS_RETCODE_PRECONDITION_NOT_MET:
 | 
			
		||||
      DDS_ILOG (DDS_LC_ERROR, id, "Inconsistent domain configuration detected: domain on configuration: %"PRIu32", domain %"PRIu32"\n", dom->m_id, id);
 | 
			
		||||
    case DDS_RETCODE_NOT_FOUND:
 | 
			
		||||
      dom = dds_alloc (sizeof (*dom));
 | 
			
		||||
      if ((ret = dds_domain_init (dom, id, config)) < 0)
 | 
			
		||||
        dds_free (dom);
 | 
			
		||||
      else
 | 
			
		||||
      {
 | 
			
		||||
        ddsrt_mutex_lock (&dom->m_entity.m_mutex);
 | 
			
		||||
        ddsrt_avl_insert (&dds_domaintree_def, &dds_global.m_domains, dom);
 | 
			
		||||
        dds_entity_register_child (&dds_global.m_entity, &dom->m_entity);
 | 
			
		||||
        dds_entity_add_ref_locked (&dom->m_entity);
 | 
			
		||||
        ddsrt_mutex_unlock (&dom->m_entity.m_mutex);
 | 
			
		||||
        *domain_out = dom;
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
  }
 | 
			
		||||
  ddsrt_mutex_unlock (&dds_global.m_mutex);
 | 
			
		||||
  return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dds_domain_free (dds_domain *domain)
 | 
			
		||||
dds_return_t dds_create_domain(const dds_domainid_t domain, const char *config)
 | 
			
		||||
{
 | 
			
		||||
  dds_domain *dom;
 | 
			
		||||
  dds_entity_t ret;
 | 
			
		||||
 | 
			
		||||
  if (domain == DDS_DOMAIN_DEFAULT || config == NULL)
 | 
			
		||||
    return DDS_RETCODE_BAD_PARAMETER;
 | 
			
		||||
 | 
			
		||||
  /* Make sure DDS instance is initialized. */
 | 
			
		||||
  if ((ret = dds_init ()) < 0)
 | 
			
		||||
    goto err_dds_init;
 | 
			
		||||
 | 
			
		||||
  if ((ret = dds_domain_create_internal (&dom, domain, false, config)) < 0)
 | 
			
		||||
    goto err_domain_create;
 | 
			
		||||
 | 
			
		||||
  return DDS_RETCODE_OK;
 | 
			
		||||
 | 
			
		||||
err_domain_create:
 | 
			
		||||
  dds_delete_impl_pinned (&dds_global.m_entity, DIS_EXPLICIT);
 | 
			
		||||
err_dds_init:
 | 
			
		||||
  return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static dds_return_t dds_domain_free (dds_entity *vdomain)
 | 
			
		||||
{
 | 
			
		||||
  struct dds_domain *domain = (struct dds_domain *) vdomain;
 | 
			
		||||
  rtps_stop (&domain->gv);
 | 
			
		||||
  dds__builtin_fini (domain);
 | 
			
		||||
 | 
			
		||||
  if (domain->gv.config.liveliness_monitoring)
 | 
			
		||||
    ddsi_threadmon_unregister_domain (dds_global.threadmon, &domain->gv);
 | 
			
		||||
 | 
			
		||||
  rtps_fini (&domain->gv);
 | 
			
		||||
 | 
			
		||||
  /* tearing down the top-level object has more consequences, so it waits until signalled that all
 | 
			
		||||
     domains have been removed */
 | 
			
		||||
  ddsrt_mutex_lock (&dds_global.m_mutex);
 | 
			
		||||
  if (--domain->m_refc != 0)
 | 
			
		||||
  if (domain->gv.config.liveliness_monitoring && --dds_global.threadmon_count == 0)
 | 
			
		||||
  {
 | 
			
		||||
    ddsrt_mutex_unlock (&dds_global.m_mutex);
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
    ddsrt_avl_delete (&dds_domaintree_def, &dds_global.m_domains, domain);
 | 
			
		||||
    ddsrt_mutex_unlock (&dds_global.m_mutex);
 | 
			
		||||
    dds_domain_fini (domain);
 | 
			
		||||
    dds_free (domain);
 | 
			
		||||
    ddsi_threadmon_stop (dds_global.threadmon);
 | 
			
		||||
    ddsi_threadmon_free (dds_global.threadmon);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ddsrt_avl_delete (&dds_domaintree_def, &dds_global.m_domains, domain);
 | 
			
		||||
  dds_entity_final_deinit_before_free (vdomain);
 | 
			
		||||
  config_fini (domain->cfgst);
 | 
			
		||||
  dds_free (vdomain);
 | 
			
		||||
  ddsrt_cond_broadcast (&dds_global.m_cond);
 | 
			
		||||
  ddsrt_mutex_unlock (&dds_global.m_mutex);
 | 
			
		||||
  return DDS_RETCODE_NO_DATA;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#include "dds__entity.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -295,7 +342,8 @@ void dds_write_set_batch (bool enable)
 | 
			
		|||
  /* FIXME: get channels + latency budget working and get rid of this; in the mean time, any ugly hack will do.  */
 | 
			
		||||
  struct dds_domain *dom;
 | 
			
		||||
  dds_domainid_t next_id = 0;
 | 
			
		||||
  dds_init ();
 | 
			
		||||
  if (dds_init () < 0)
 | 
			
		||||
    return;
 | 
			
		||||
  ddsrt_mutex_lock (&dds_global.m_mutex);
 | 
			
		||||
  while ((dom = ddsrt_avl_lookup_succ_eq (&dds_domaintree_def, &dds_global.m_domains, &next_id)) != NULL)
 | 
			
		||||
  {
 | 
			
		||||
| 
						 | 
				
			
			@ -306,7 +354,7 @@ void dds_write_set_batch (bool enable)
 | 
			
		|||
 | 
			
		||||
    dds_instance_handle_t last_iid = 0;
 | 
			
		||||
    struct dds_entity *e;
 | 
			
		||||
    while (dom && (e = ddsrt_avl_lookup_succ (&dds_entity_children_td, &dom->m_ppants, &last_iid)) != NULL)
 | 
			
		||||
    while (dom && (e = ddsrt_avl_lookup_succ (&dds_entity_children_td, &dom->m_entity.m_children, &last_iid)) != NULL)
 | 
			
		||||
    {
 | 
			
		||||
      struct dds_entity *x;
 | 
			
		||||
      last_iid = e->m_iid;
 | 
			
		||||
| 
						 | 
				
			
			@ -321,5 +369,5 @@ void dds_write_set_batch (bool enable)
 | 
			
		|||
    }
 | 
			
		||||
  }
 | 
			
		||||
  ddsrt_mutex_unlock (&dds_global.m_mutex);
 | 
			
		||||
  dds_fini ();
 | 
			
		||||
  dds_delete_impl_pinned (&dds_global.m_entity, DIS_EXPLICIT);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -40,10 +40,15 @@ const struct dds_entity_deriver *dds_entity_deriver_table[] = {
 | 
			
		|||
  [DDS_KIND_COND_QUERY] = &dds_entity_deriver_readcondition,
 | 
			
		||||
  [DDS_KIND_COND_GUARD] = &dds_entity_deriver_guardcondition,
 | 
			
		||||
  [DDS_KIND_WAITSET] = &dds_entity_deriver_waitset,
 | 
			
		||||
  [DDS_KIND_DOMAIN] = &dds_entity_deriver_domain,
 | 
			
		||||
  [DDS_KIND_CYCLONEDDS] = &dds_entity_deriver_cyclonedds
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
dds_return_t dds_entity_deriver_dummy_close (struct dds_entity *e) {
 | 
			
		||||
  (void) e; return DDS_RETCODE_OK;
 | 
			
		||||
void dds_entity_deriver_dummy_interrupt (struct dds_entity *e) {
 | 
			
		||||
  (void) e;
 | 
			
		||||
}
 | 
			
		||||
void dds_entity_deriver_dummy_close (struct dds_entity *e) {
 | 
			
		||||
  (void) e;
 | 
			
		||||
}
 | 
			
		||||
dds_return_t dds_entity_deriver_dummy_delete (struct dds_entity *e) {
 | 
			
		||||
  (void) e; return DDS_RETCODE_OK;
 | 
			
		||||
| 
						 | 
				
			
			@ -55,7 +60,8 @@ dds_return_t dds_entity_deriver_dummy_validate_status (uint32_t mask) {
 | 
			
		|||
  (void) mask; return DDS_RETCODE_ILLEGAL_OPERATION;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
extern inline dds_return_t dds_entity_deriver_close (struct dds_entity *e);
 | 
			
		||||
extern inline void dds_entity_deriver_interrupt (struct dds_entity *e);
 | 
			
		||||
extern inline void dds_entity_deriver_close (struct dds_entity *e);
 | 
			
		||||
extern inline dds_return_t dds_entity_deriver_delete (struct dds_entity *e);
 | 
			
		||||
extern inline dds_return_t dds_entity_deriver_set_qos (struct dds_entity *e, const dds_qos_t *qos, bool enabled);
 | 
			
		||||
extern inline dds_return_t dds_entity_deriver_validate_status (struct dds_entity *e, uint32_t mask);
 | 
			
		||||
| 
						 | 
				
			
			@ -73,23 +79,12 @@ const ddsrt_avl_treedef_t dds_entity_children_td = DDSRT_AVL_TREEDEF_INITIALIZER
 | 
			
		|||
 | 
			
		||||
static void dds_entity_observers_signal (dds_entity *observed, uint32_t status);
 | 
			
		||||
static void dds_entity_observers_signal_delete (dds_entity *observed);
 | 
			
		||||
static void dds_entity_observers_delete (dds_entity *observed);
 | 
			
		||||
 | 
			
		||||
void dds_entity_add_ref_locked (dds_entity *e)
 | 
			
		||||
{
 | 
			
		||||
  dds_handle_add_ref (&e->m_hdllink);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dds_domain *dds__entity_domain (dds_entity *e)
 | 
			
		||||
{
 | 
			
		||||
  return e->m_domain;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static dds_entity *dds__nonself_parent (dds_entity *e)
 | 
			
		||||
{
 | 
			
		||||
  return e->m_parent == e ? NULL : e->m_parent;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool entity_has_status (const dds_entity *e)
 | 
			
		||||
{
 | 
			
		||||
  switch (e->m_kind)
 | 
			
		||||
| 
						 | 
				
			
			@ -105,6 +100,8 @@ static bool entity_has_status (const dds_entity *e)
 | 
			
		|||
    case DDS_KIND_COND_QUERY:
 | 
			
		||||
    case DDS_KIND_COND_GUARD:
 | 
			
		||||
    case DDS_KIND_WAITSET:
 | 
			
		||||
    case DDS_KIND_DOMAIN:
 | 
			
		||||
    case DDS_KIND_CYCLONEDDS:
 | 
			
		||||
      break;
 | 
			
		||||
    case DDS_KIND_DONTCARE:
 | 
			
		||||
      abort ();
 | 
			
		||||
| 
						 | 
				
			
			@ -117,12 +114,13 @@ dds_entity_t dds_entity_init (dds_entity *e, dds_entity *parent, dds_entity_kind
 | 
			
		|||
{
 | 
			
		||||
  dds_handle_t handle;
 | 
			
		||||
 | 
			
		||||
  assert ((kind == DDS_KIND_PARTICIPANT) == (parent == NULL));
 | 
			
		||||
  assert ((kind == DDS_KIND_CYCLONEDDS) == (parent == NULL));
 | 
			
		||||
  assert (e);
 | 
			
		||||
 | 
			
		||||
  e->m_kind = kind;
 | 
			
		||||
  e->m_qos = qos;
 | 
			
		||||
  e->m_cb_count = 0;
 | 
			
		||||
  e->m_cb_pending_count = 0;
 | 
			
		||||
  e->m_observers = NULL;
 | 
			
		||||
 | 
			
		||||
  /* TODO: CHAM-96: Implement dynamic enabling of entity. */
 | 
			
		||||
| 
						 | 
				
			
			@ -143,14 +141,14 @@ dds_entity_t dds_entity_init (dds_entity *e, dds_entity *parent, dds_entity_kind
 | 
			
		|||
  {
 | 
			
		||||
    e->m_parent = parent;
 | 
			
		||||
    e->m_domain = parent->m_domain;
 | 
			
		||||
    e->m_participant = parent->m_participant;
 | 
			
		||||
    ddsrt_avl_init (&dds_entity_children_td, &e->m_children);
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
    e->m_participant = e;
 | 
			
		||||
    e->m_parent = e;
 | 
			
		||||
    assert (kind == DDS_KIND_CYCLONEDDS);
 | 
			
		||||
    e->m_parent = NULL;
 | 
			
		||||
    e->m_domain = NULL;
 | 
			
		||||
  }
 | 
			
		||||
  ddsrt_avl_init (&dds_entity_children_td, &e->m_children);
 | 
			
		||||
 | 
			
		||||
  dds_reset_listener (&e->m_listener);
 | 
			
		||||
  if (listener)
 | 
			
		||||
| 
						 | 
				
			
			@ -162,13 +160,26 @@ dds_entity_t dds_entity_init (dds_entity *e, dds_entity *parent, dds_entity_kind
 | 
			
		|||
    ddsrt_mutex_unlock (&parent->m_observers_lock);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if ((handle = dds_handle_create (&e->m_hdllink)) <= 0)
 | 
			
		||||
    return (dds_entity_t) handle;
 | 
			
		||||
  if (kind == DDS_KIND_CYCLONEDDS)
 | 
			
		||||
  {
 | 
			
		||||
    if ((handle = dds_handle_register_special (&e->m_hdllink, DDS_CYCLONEDDS_HANDLE)) <= 0)
 | 
			
		||||
      return (dds_entity_t) handle;
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
    if ((handle = dds_handle_create (&e->m_hdllink)) <= 0)
 | 
			
		||||
      return (dds_entity_t) handle;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /* An dds_handle_t is directly used as dds_entity_t. */
 | 
			
		||||
  return (dds_entity_t) handle;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dds_entity_init_complete (dds_entity *entity)
 | 
			
		||||
{
 | 
			
		||||
  dds_handle_unpend (&entity->m_hdllink);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dds_entity_register_child (dds_entity *parent, dds_entity *child)
 | 
			
		||||
{
 | 
			
		||||
  assert (child->m_iid != 0);
 | 
			
		||||
| 
						 | 
				
			
			@ -176,11 +187,6 @@ void dds_entity_register_child (dds_entity *parent, dds_entity *child)
 | 
			
		|||
  ddsrt_avl_insert (&dds_entity_children_td, &parent->m_children, child);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dds_return_t dds_delete (dds_entity_t entity)
 | 
			
		||||
{
 | 
			
		||||
  return dds_delete_impl (entity, false);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static dds_entity *next_non_topic_child (ddsrt_avl_tree_t *remaining_children)
 | 
			
		||||
{
 | 
			
		||||
  ddsrt_avl_iter_t it;
 | 
			
		||||
| 
						 | 
				
			
			@ -192,45 +198,145 @@ static dds_entity *next_non_topic_child (ddsrt_avl_tree_t *remaining_children)
 | 
			
		|||
  return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dds_return_t dds_delete_impl (dds_entity_t entity, bool keep_if_explicit)
 | 
			
		||||
#define TRACE_DELETE 0 /* FIXME: use DDS_LOG for this */
 | 
			
		||||
#if TRACE_DELETE
 | 
			
		||||
static const char *entity_kindstr (dds_entity_kind_t kind)
 | 
			
		||||
{
 | 
			
		||||
  switch (kind)
 | 
			
		||||
  {
 | 
			
		||||
    case DDS_KIND_TOPIC: return "topic";
 | 
			
		||||
    case DDS_KIND_READER: return "reader";
 | 
			
		||||
    case DDS_KIND_WRITER: return "writer";
 | 
			
		||||
    case DDS_KIND_PUBLISHER: return "publisher";
 | 
			
		||||
    case DDS_KIND_SUBSCRIBER: return "subscriber";
 | 
			
		||||
    case DDS_KIND_PARTICIPANT: return "participant";
 | 
			
		||||
    case DDS_KIND_COND_READ: return "readcond";
 | 
			
		||||
    case DDS_KIND_COND_QUERY: return "querycond";
 | 
			
		||||
    case DDS_KIND_COND_GUARD: return "guardcond";
 | 
			
		||||
    case DDS_KIND_WAITSET: return "waitset";
 | 
			
		||||
    case DDS_KIND_DOMAIN: return "domain";
 | 
			
		||||
    case DDS_KIND_CYCLONEDDS: return "cyclonedds";
 | 
			
		||||
    case DDS_KIND_DONTCARE: break;
 | 
			
		||||
  }
 | 
			
		||||
  return "UNDEF";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void print_delete (const dds_entity *e, enum delete_impl_state delstate , dds_instance_handle_t iid)
 | 
			
		||||
{
 | 
			
		||||
  unsigned cm = ddsrt_atomic_ld32 (&e->m_hdllink.cnt_flags);
 | 
			
		||||
  printf ("delete(%p, delstate %s, iid %"PRIx64"): %s%s %d pin %u refc %u %s %s\n",
 | 
			
		||||
          (void *) e, (delstate == DIS_IMPLICIT) ? "implicit" : (delstate == DIS_EXPLICIT) ? "explicit" : "from_parent", iid,
 | 
			
		||||
          entity_kindstr (e->m_kind), (e->m_flags & DDS_ENTITY_IMPLICIT) ? " [implicit]" : "",
 | 
			
		||||
          e->m_hdllink.hdl, cm & 0xfff, (cm >> 12) & 0xffff, (cm & 0x80000000) ? "closed" : "open",
 | 
			
		||||
          ddsrt_avl_is_empty (&e->m_children) ? "childless" : "has-children");
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static dds_return_t dds_delete_impl (dds_entity_t entity, enum delete_impl_state delstate);
 | 
			
		||||
 | 
			
		||||
dds_return_t dds_delete (dds_entity_t entity)
 | 
			
		||||
{
 | 
			
		||||
  return dds_delete_impl (entity, DIS_EXPLICIT);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dds_entity_final_deinit_before_free (dds_entity *e)
 | 
			
		||||
{
 | 
			
		||||
  dds_delete_qos (e->m_qos);
 | 
			
		||||
  ddsrt_cond_destroy (&e->m_cond);
 | 
			
		||||
  ddsrt_cond_destroy (&e->m_observers_cond);
 | 
			
		||||
  ddsrt_mutex_destroy (&e->m_mutex);
 | 
			
		||||
  ddsrt_mutex_destroy (&e->m_observers_lock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static dds_return_t dds_delete_impl (dds_entity_t entity, enum delete_impl_state delstate)
 | 
			
		||||
{
 | 
			
		||||
  dds_time_t timeout = DDS_SECS(10);
 | 
			
		||||
  dds_entity *e;
 | 
			
		||||
  dds_return_t ret;
 | 
			
		||||
  if ((ret = dds_entity_pin (entity, &e)) < 0)
 | 
			
		||||
    return ret;
 | 
			
		||||
  else
 | 
			
		||||
    return dds_delete_impl_pinned (e, delstate);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dds_return_t dds_delete_impl_pinned (dds_entity *e, enum delete_impl_state delstate)
 | 
			
		||||
{
 | 
			
		||||
  dds_entity *child;
 | 
			
		||||
  dds_return_t ret;
 | 
			
		||||
  dds_return_t rc;
 | 
			
		||||
 | 
			
		||||
  if ((rc = dds_entity_pin (entity, &e)) < 0)
 | 
			
		||||
    return rc;
 | 
			
		||||
  /* Any number of threads pinning it, possibly in delete, or having pinned it and
 | 
			
		||||
     trying to acquire m_mutex */
 | 
			
		||||
 | 
			
		||||
  ddsrt_mutex_lock (&e->m_mutex);
 | 
			
		||||
  if (keep_if_explicit == true && (e->m_flags & DDS_ENTITY_IMPLICIT) == 0)
 | 
			
		||||
#if TRACE_DELETE
 | 
			
		||||
  print_delete (e, delstate, iid);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  /* If another thread was racing us in delete, it will have set the CLOSING flag
 | 
			
		||||
     while holding m_mutex and we had better bail out. */
 | 
			
		||||
  if (dds_handle_is_closed (&e->m_hdllink))
 | 
			
		||||
  {
 | 
			
		||||
    ddsrt_mutex_unlock (&e->m_mutex);
 | 
			
		||||
    dds_entity_unpin (e);
 | 
			
		||||
    dds_entity_unlock (e);
 | 
			
		||||
    return DDS_RETCODE_OK;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /* Ignore children calling up to delete an implicit parent if there are still
 | 
			
		||||
     (or again) children */
 | 
			
		||||
  if (delstate == DIS_IMPLICIT)
 | 
			
		||||
  {
 | 
			
		||||
    if (!((e->m_flags & DDS_ENTITY_IMPLICIT) && ddsrt_avl_is_empty (&e->m_children)))
 | 
			
		||||
    {
 | 
			
		||||
      dds_entity_unlock (e);
 | 
			
		||||
      return DDS_RETCODE_OK;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /* Drop reference, atomically setting CLOSING if no other references remain.
 | 
			
		||||
     FIXME: that's not quite right: this is really only for topics.  After a call
 | 
			
		||||
     to delete, the handle ought to become invalid even if the topic stays (and
 | 
			
		||||
     should perhaps even be revivable via find_topic). */
 | 
			
		||||
  if (! dds_handle_drop_ref (&e->m_hdllink))
 | 
			
		||||
  {
 | 
			
		||||
    ddsrt_mutex_unlock (&e->m_mutex);
 | 
			
		||||
    dds_entity_unpin (e);
 | 
			
		||||
    dds_entity_unlock (e);
 | 
			
		||||
    return DDS_RETCODE_OK;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /* No threads pinning it anymore, no need to worry about other threads deleting
 | 
			
		||||
     it, but there can still be plenty of threads that have it pinned and are
 | 
			
		||||
     trying to acquire m_mutex to do their thing (including creating children,
 | 
			
		||||
     attaching to waitsets, &c.) */
 | 
			
		||||
 | 
			
		||||
  assert (dds_handle_is_closed (&e->m_hdllink));
 | 
			
		||||
 | 
			
		||||
  /* Trigger blocked threads (and, still, delete DDSI reader/writer to trigger
 | 
			
		||||
     continued cleanup -- while that's quite safe given that GUIDs don't get
 | 
			
		||||
     reused quickly, it needs an update) */
 | 
			
		||||
  dds_entity_deriver_interrupt (e);
 | 
			
		||||
 | 
			
		||||
  /* Prevent further listener invocations; dds_set_status_mask locks m_mutex and
 | 
			
		||||
     checks for a pending delete to guarantee that once we clear the mask here,
 | 
			
		||||
     no new listener invocations will occur beyond those already in progress.
 | 
			
		||||
     (FIXME: or committed to?  I think in-progress only, better check.) */
 | 
			
		||||
  ddsrt_mutex_lock (&e->m_observers_lock);
 | 
			
		||||
  if (entity_has_status (e))
 | 
			
		||||
    ddsrt_atomic_and32 (&e->m_status.m_status_and_mask, SAM_STATUS_MASK);
 | 
			
		||||
  dds_reset_listener (&e->m_listener);
 | 
			
		||||
 | 
			
		||||
  /* Signal observers that this entity will be deleted and wait for
 | 
			
		||||
     all listeners to complete. */
 | 
			
		||||
  ddsrt_mutex_unlock (&e->m_mutex);
 | 
			
		||||
  dds_entity_observers_signal_delete (e);
 | 
			
		||||
  while (e->m_cb_count > 0)
 | 
			
		||||
 | 
			
		||||
  /* wait for all listeners to complete - FIXME: rely on pincount instead?
 | 
			
		||||
     that would require all listeners to pin the entity instead, but it
 | 
			
		||||
     would prevent them from doing much. */
 | 
			
		||||
  while (e->m_cb_pending_count > 0)
 | 
			
		||||
    ddsrt_cond_wait (&e->m_observers_cond, &e->m_observers_lock);
 | 
			
		||||
  ddsrt_mutex_unlock (&e->m_observers_lock);
 | 
			
		||||
 | 
			
		||||
  /* Wait for all other threads to unpin the entity */
 | 
			
		||||
  dds_handle_close_wait (&e->m_hdllink);
 | 
			
		||||
 | 
			
		||||
  /* Pin count dropped to one with CLOSING flag set: no other threads still
 | 
			
		||||
     in operations involving this entity */
 | 
			
		||||
  dds_entity_observers_signal_delete (e);
 | 
			
		||||
  dds_entity_deriver_close (e);
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Recursively delete children.
 | 
			
		||||
   *
 | 
			
		||||
| 
						 | 
				
			
			@ -248,106 +354,123 @@ dds_return_t dds_delete_impl (dds_entity_t entity, bool keep_if_explicit)
 | 
			
		|||
   *
 | 
			
		||||
   * To circumvent the problem. We ignore topics in the first loop.
 | 
			
		||||
   */
 | 
			
		||||
  ret = DDS_RETCODE_OK;
 | 
			
		||||
  ddsrt_mutex_lock (&e->m_mutex);
 | 
			
		||||
  while ((child = next_non_topic_child (&e->m_children)) && ret == DDS_RETCODE_OK)
 | 
			
		||||
  while ((child = next_non_topic_child (&e->m_children)) != NULL)
 | 
			
		||||
  {
 | 
			
		||||
    /* FIXME: dds_delete can fail if the child is being deleted in parallel, in which case: wait */
 | 
			
		||||
    dds_entity_t child_handle = child->m_hdllink.hdl;
 | 
			
		||||
    ddsrt_mutex_unlock (&e->m_mutex);
 | 
			
		||||
    ret = dds_delete (child_handle);
 | 
			
		||||
    (void) dds_delete_impl (child_handle, DIS_FROM_PARENT);
 | 
			
		||||
    ddsrt_mutex_lock (&e->m_mutex);
 | 
			
		||||
  }
 | 
			
		||||
  while ((child = ddsrt_avl_find_min (&dds_entity_children_td, &e->m_children)) != NULL && ret == DDS_RETCODE_OK)
 | 
			
		||||
  while ((child = ddsrt_avl_find_min (&dds_entity_children_td, &e->m_children)) != NULL)
 | 
			
		||||
  {
 | 
			
		||||
    assert (dds_entity_kind (child) == DDS_KIND_TOPIC);
 | 
			
		||||
    dds_entity_t child_handle = child->m_hdllink.hdl;
 | 
			
		||||
    ddsrt_mutex_unlock (&e->m_mutex);
 | 
			
		||||
    ret = dds_delete (child_handle);
 | 
			
		||||
    (void) dds_delete_impl (child_handle, DIS_FROM_PARENT);
 | 
			
		||||
    ddsrt_mutex_lock (&e->m_mutex);
 | 
			
		||||
  }
 | 
			
		||||
  ddsrt_mutex_unlock (&e->m_mutex);
 | 
			
		||||
  if (ret == DDS_RETCODE_OK)
 | 
			
		||||
    ret = dds_entity_deriver_close (e);
 | 
			
		||||
 | 
			
		||||
  dds_entity_unpin (e);
 | 
			
		||||
  if (ret == DDS_RETCODE_OK)
 | 
			
		||||
  /* The dds_handle_delete will wait until the last active claim on that handle is
 | 
			
		||||
     released. It is possible that this last release will be done by a thread that was
 | 
			
		||||
     kicked during the close(). */
 | 
			
		||||
  ret = dds_handle_delete (&e->m_hdllink);
 | 
			
		||||
  assert (ret == DDS_RETCODE_OK);
 | 
			
		||||
  (void) ret;
 | 
			
		||||
 | 
			
		||||
  /* Remove from parent; schedule deletion of parent if it was created implicitly, no
 | 
			
		||||
     longer has any remaining children, and we didn't arrive here as a consequence of
 | 
			
		||||
     deleting the parent. */
 | 
			
		||||
  dds_entity *parent_to_delete = NULL;
 | 
			
		||||
  if (e->m_parent != NULL)
 | 
			
		||||
  {
 | 
			
		||||
    /* The dds_handle_delete will wait until the last active claim on that handle
 | 
			
		||||
     * is released. It is possible that this last release will be done by a thread
 | 
			
		||||
     * that was kicked during the close(). */
 | 
			
		||||
    if ((ret = dds_handle_delete (&e->m_hdllink, timeout)) != DDS_RETCODE_OK)
 | 
			
		||||
      return ret;
 | 
			
		||||
  }
 | 
			
		||||
    struct dds_entity * const p = e->m_parent;
 | 
			
		||||
 | 
			
		||||
  if (ret == DDS_RETCODE_OK)
 | 
			
		||||
  {
 | 
			
		||||
    /* Remove all possible observers. */
 | 
			
		||||
    dds_entity_observers_delete (e);
 | 
			
		||||
    ddsrt_mutex_lock (&p->m_mutex);
 | 
			
		||||
    assert (ddsrt_avl_lookup (&dds_entity_children_td, &p->m_children, &e->m_iid) != NULL);
 | 
			
		||||
    ddsrt_avl_delete (&dds_entity_children_td, &p->m_children, e);
 | 
			
		||||
    /* trigger parent in case it is waiting in delete */
 | 
			
		||||
    ddsrt_cond_broadcast (&p->m_cond);
 | 
			
		||||
 | 
			
		||||
    /* Remove from parent */
 | 
			
		||||
    dds_entity *parent;
 | 
			
		||||
    if ((parent = dds__nonself_parent(e)) != NULL)
 | 
			
		||||
    if (delstate != DIS_FROM_PARENT && (p->m_flags & DDS_ENTITY_IMPLICIT) && ddsrt_avl_is_empty (&p->m_children))
 | 
			
		||||
    {
 | 
			
		||||
      ddsrt_mutex_lock (&parent->m_mutex);
 | 
			
		||||
      assert (ddsrt_avl_lookup (&dds_entity_children_td, &parent->m_children, &e->m_iid) != NULL);
 | 
			
		||||
      ddsrt_avl_delete (&dds_entity_children_td, &parent->m_children, e);
 | 
			
		||||
      ddsrt_mutex_unlock (&parent->m_mutex);
 | 
			
		||||
      if ((ret = dds_entity_pin (p->m_hdllink.hdl, &parent_to_delete)) < 0)
 | 
			
		||||
        parent_to_delete = NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Do some specific deletion when needed. */
 | 
			
		||||
    ret = dds_entity_deriver_delete (e);
 | 
			
		||||
    ddsrt_mutex_unlock (&p->m_mutex);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (ret == DDS_RETCODE_OK)
 | 
			
		||||
  /* Do some specific deletion when needed */
 | 
			
		||||
  ret = dds_entity_deriver_delete (e);
 | 
			
		||||
  if (ret == DDS_RETCODE_NO_DATA)
 | 
			
		||||
  {
 | 
			
		||||
    dds_delete_qos (e->m_qos);
 | 
			
		||||
    ddsrt_cond_destroy (&e->m_cond);
 | 
			
		||||
    ddsrt_cond_destroy (&e->m_observers_cond);
 | 
			
		||||
    ddsrt_mutex_destroy (&e->m_mutex);
 | 
			
		||||
    ddsrt_mutex_destroy (&e->m_observers_lock);
 | 
			
		||||
    /* Bootstrapping and its inverse are always a tricky business, and here it is no different:
 | 
			
		||||
       deleting the pseudo-top-level object tears down all kinds of stuff that is supposed to
 | 
			
		||||
       remain in existence (like the entire platform abstraction) and so it must be the final
 | 
			
		||||
       call.  Thus, we rely on it to call "dds_entity_final_deinit_before_free" and return a
 | 
			
		||||
       special error code that we don't pass on to the caller. */
 | 
			
		||||
    ret = DDS_RETCODE_OK;
 | 
			
		||||
  }
 | 
			
		||||
  else if (ret != DDS_RETCODE_OK)
 | 
			
		||||
  {
 | 
			
		||||
    if (parent_to_delete)
 | 
			
		||||
      dds_entity_unpin (parent_to_delete);
 | 
			
		||||
    return ret;
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
    dds_entity_final_deinit_before_free (e);
 | 
			
		||||
    dds_free (e);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return ret;
 | 
			
		||||
  assert (ret == DDS_RETCODE_OK);
 | 
			
		||||
  (void) ret;
 | 
			
		||||
  return (parent_to_delete != NULL) ? dds_delete_impl_pinned (parent_to_delete, DIS_IMPLICIT) : DDS_RETCODE_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool dds_entity_in_scope (const dds_entity *e, const dds_entity *root)
 | 
			
		||||
{
 | 
			
		||||
  /* An entity is not an ancestor of itself */
 | 
			
		||||
  while (e != NULL && e != root)
 | 
			
		||||
    e = e->m_parent;
 | 
			
		||||
  return (e != NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dds_entity_t dds_get_parent (dds_entity_t entity)
 | 
			
		||||
{
 | 
			
		||||
  dds_entity *e;
 | 
			
		||||
  dds_return_t rc;
 | 
			
		||||
  if ((rc = dds_entity_lock (entity, DDS_KIND_DONTCARE, &e)) != DDS_RETCODE_OK)
 | 
			
		||||
  if ((rc = dds_entity_pin (entity, &e)) != DDS_RETCODE_OK)
 | 
			
		||||
    return rc;
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
    dds_entity *parent;
 | 
			
		||||
    dds_entity_t hdl;
 | 
			
		||||
    if ((parent = dds__nonself_parent(e)) == NULL)
 | 
			
		||||
      hdl = DDS_ENTITY_NIL;
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
      dds_entity *x;
 | 
			
		||||
      hdl = parent->m_hdllink.hdl;
 | 
			
		||||
      if (dds_entity_lock (hdl, DDS_KIND_DONTCARE, &x) == DDS_RETCODE_OK)
 | 
			
		||||
      {
 | 
			
		||||
        parent->m_flags &= ~DDS_ENTITY_IMPLICIT;
 | 
			
		||||
        dds_entity_unlock (parent);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    dds_entity_unlock (e);
 | 
			
		||||
    dds_entity_t hdl = e->m_parent ? e->m_parent->m_hdllink.hdl : 0;
 | 
			
		||||
    dds_entity_unpin (e);
 | 
			
		||||
    return hdl;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dds_participant *dds_entity_participant (dds_entity *e)
 | 
			
		||||
{
 | 
			
		||||
  while (e && dds_entity_kind (e) != DDS_KIND_PARTICIPANT)
 | 
			
		||||
    e = e->m_parent;
 | 
			
		||||
  return (dds_participant *) e;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dds_entity_t dds_get_participant (dds_entity_t entity)
 | 
			
		||||
{
 | 
			
		||||
  dds_entity *e;
 | 
			
		||||
  dds_return_t rc;
 | 
			
		||||
  if ((rc = dds_entity_lock (entity, DDS_KIND_DONTCARE, &e)) != DDS_RETCODE_OK)
 | 
			
		||||
  if ((rc = dds_entity_pin (entity, &e)) != DDS_RETCODE_OK)
 | 
			
		||||
    return rc;
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
    dds_entity_t hdl = e->m_participant->m_hdllink.hdl;
 | 
			
		||||
    dds_entity_unlock (e);
 | 
			
		||||
    dds_participant *par = dds_entity_participant (e);
 | 
			
		||||
    dds_entity_t hdl = par ? par->m_entity.m_hdllink.hdl : 0;
 | 
			
		||||
    dds_entity_unpin (e);
 | 
			
		||||
    return hdl;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -357,42 +480,28 @@ dds_return_t dds_get_children (dds_entity_t entity, dds_entity_t *children, size
 | 
			
		|||
  dds_entity *e;
 | 
			
		||||
  dds_return_t rc;
 | 
			
		||||
 | 
			
		||||
  if (children != NULL && (size <= 0 || size >= INT32_MAX))
 | 
			
		||||
    return DDS_RETCODE_BAD_PARAMETER;
 | 
			
		||||
  if (children == NULL && size != 0)
 | 
			
		||||
  if ((children != NULL && (size == 0 || size > INT32_MAX)) || (children == NULL && size != 0))
 | 
			
		||||
    return DDS_RETCODE_BAD_PARAMETER;
 | 
			
		||||
 | 
			
		||||
  if ((rc = dds_entity_pin (entity, &e)) != DDS_RETCODE_OK)
 | 
			
		||||
    return rc;
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
    /* FIXME: fix the implicit/explicit stuff so the set_explicit isn't needed; and then this can also be done with a regular iterator & without unlocking */
 | 
			
		||||
    ddsrt_avl_iter_t it;
 | 
			
		||||
    size_t n = 0;
 | 
			
		||||
    dds_instance_handle_t last_iid = 0;
 | 
			
		||||
    struct dds_entity *c;
 | 
			
		||||
    ddsrt_mutex_lock (&e->m_mutex);
 | 
			
		||||
    while ((c = ddsrt_avl_lookup_succ (&dds_entity_children_td, &e->m_children, &last_iid)) != NULL)
 | 
			
		||||
    for (c = ddsrt_avl_iter_first (&dds_entity_children_td, &e->m_children, &it); c != NULL; c = ddsrt_avl_iter_next (&it))
 | 
			
		||||
    {
 | 
			
		||||
      last_iid = c->m_iid;
 | 
			
		||||
      if (n < size)
 | 
			
		||||
      struct dds_entity *tmp;
 | 
			
		||||
      /* Attempt at pinning the entity will fail if it is still pending */
 | 
			
		||||
      if (dds_entity_pin (c->m_hdllink.hdl, &tmp) == DDS_RETCODE_OK)
 | 
			
		||||
      {
 | 
			
		||||
        dds_entity *x;
 | 
			
		||||
        /* Claim child handle to guarantee the child entity remains valid; as we unlock "e" only when we manage to claim the child, and the child has to remain in existence until we release it, "c" remains a valid pointer despite the unlocking. */
 | 
			
		||||
        if (dds_entity_pin (c->m_hdllink.hdl, &x) == DDS_RETCODE_OK)
 | 
			
		||||
        {
 | 
			
		||||
          assert (x == c);
 | 
			
		||||
        if (n < size)
 | 
			
		||||
          children[n] = c->m_hdllink.hdl;
 | 
			
		||||
          ddsrt_mutex_unlock (&e->m_mutex);
 | 
			
		||||
 | 
			
		||||
          ddsrt_mutex_lock (&c->m_mutex);
 | 
			
		||||
          c->m_flags &= ~DDS_ENTITY_IMPLICIT;
 | 
			
		||||
          ddsrt_mutex_unlock (&c->m_mutex);
 | 
			
		||||
 | 
			
		||||
          ddsrt_mutex_lock (&e->m_mutex);
 | 
			
		||||
          dds_entity_unpin (c);
 | 
			
		||||
        }
 | 
			
		||||
        n++;
 | 
			
		||||
        dds_entity_unpin (tmp);
 | 
			
		||||
      }
 | 
			
		||||
      n++;
 | 
			
		||||
    }
 | 
			
		||||
    ddsrt_mutex_unlock (&e->m_mutex);
 | 
			
		||||
    dds_entity_unpin (e);
 | 
			
		||||
| 
						 | 
				
			
			@ -423,6 +532,8 @@ static uint64_t entity_kind_qos_mask (dds_entity_kind_t kind)
 | 
			
		|||
    case DDS_KIND_COND_QUERY:
 | 
			
		||||
    case DDS_KIND_COND_GUARD:
 | 
			
		||||
    case DDS_KIND_WAITSET:
 | 
			
		||||
    case DDS_KIND_DOMAIN:
 | 
			
		||||
    case DDS_KIND_CYCLONEDDS:
 | 
			
		||||
      break;
 | 
			
		||||
  }
 | 
			
		||||
  return 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -603,7 +714,8 @@ dds_return_t dds_set_qos (dds_entity_t entity, const dds_qos_t *qos)
 | 
			
		|||
  {
 | 
			
		||||
    case DDS_KIND_TOPIC: {
 | 
			
		||||
      dds_entity *pp;
 | 
			
		||||
      if (dds_entity_pin (e->m_participant->m_hdllink.hdl, &pp) == DDS_RETCODE_OK)
 | 
			
		||||
      assert (dds_entity_kind (e->m_parent) == DDS_KIND_PARTICIPANT);
 | 
			
		||||
      if (dds_entity_pin (e->m_parent->m_hdllink.hdl, &pp) == DDS_RETCODE_OK)
 | 
			
		||||
      {
 | 
			
		||||
        pushdown_topic_qos (pp, e);
 | 
			
		||||
        dds_entity_unpin (pp);
 | 
			
		||||
| 
						 | 
				
			
			@ -763,7 +875,7 @@ static void pushdown_listener (dds_entity *e)
 | 
			
		|||
      ddsrt_mutex_unlock (&e->m_mutex);
 | 
			
		||||
 | 
			
		||||
      ddsrt_mutex_lock (&c->m_observers_lock);
 | 
			
		||||
      while (c->m_cb_count > 0)
 | 
			
		||||
      while (c->m_cb_pending_count > 0)
 | 
			
		||||
        ddsrt_cond_wait (&c->m_observers_cond, &c->m_observers_lock);
 | 
			
		||||
 | 
			
		||||
      ddsrt_mutex_lock (&e->m_observers_lock);
 | 
			
		||||
| 
						 | 
				
			
			@ -791,7 +903,7 @@ dds_return_t dds_set_listener (dds_entity_t entity, const dds_listener_t *listen
 | 
			
		|||
    return rc;
 | 
			
		||||
 | 
			
		||||
  ddsrt_mutex_lock (&e->m_observers_lock);
 | 
			
		||||
  while (e->m_cb_count > 0)
 | 
			
		||||
  while (e->m_cb_pending_count > 0)
 | 
			
		||||
    ddsrt_cond_wait (&e->m_observers_cond, &e->m_observers_lock);
 | 
			
		||||
 | 
			
		||||
  /* new listener is constructed by combining "listener" with the ancestral listeners;
 | 
			
		||||
| 
						 | 
				
			
			@ -801,7 +913,7 @@ dds_return_t dds_set_listener (dds_entity_t entity, const dds_listener_t *listen
 | 
			
		|||
  if (listener)
 | 
			
		||||
    dds_merge_listener (&e->m_listener, listener);
 | 
			
		||||
  x = e;
 | 
			
		||||
  while (dds_entity_kind (x) != DDS_KIND_PARTICIPANT)
 | 
			
		||||
  while (dds_entity_kind (x) != DDS_KIND_CYCLONEDDS)
 | 
			
		||||
  {
 | 
			
		||||
    x = x->m_parent;
 | 
			
		||||
    ddsrt_mutex_lock (&x->m_observers_lock);
 | 
			
		||||
| 
						 | 
				
			
			@ -892,17 +1004,26 @@ dds_return_t dds_set_status_mask (dds_entity_t entity, uint32_t mask)
 | 
			
		|||
  if ((mask & ~SAM_STATUS_MASK) != 0)
 | 
			
		||||
    return DDS_RETCODE_BAD_PARAMETER;
 | 
			
		||||
 | 
			
		||||
  if ((ret = dds_entity_pin (entity, &e)) != DDS_RETCODE_OK)
 | 
			
		||||
  if ((ret = dds_entity_lock (entity, DDS_KIND_DONTCARE, &e)) != DDS_RETCODE_OK)
 | 
			
		||||
    return ret;
 | 
			
		||||
 | 
			
		||||
  if (dds_handle_is_closed (&e->m_hdllink))
 | 
			
		||||
  {
 | 
			
		||||
    /* The sole reason for locking the mutex was so we can do this atomically with
 | 
			
		||||
       respect to dds_delete (which in turn requires checking whether the handle
 | 
			
		||||
       is still open), because delete relies on the mask to shut down all listener
 | 
			
		||||
       invocations.  */
 | 
			
		||||
    dds_entity_unlock (e);
 | 
			
		||||
    return DDS_RETCODE_PRECONDITION_NOT_MET;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if ((ret = dds_entity_deriver_validate_status (e, mask)) == DDS_RETCODE_OK)
 | 
			
		||||
  {
 | 
			
		||||
    assert (entity_has_status (e));
 | 
			
		||||
    ddsrt_mutex_lock (&e->m_observers_lock);
 | 
			
		||||
    while (e->m_cb_count > 0)
 | 
			
		||||
    while (e->m_cb_pending_count > 0)
 | 
			
		||||
      ddsrt_cond_wait (&e->m_observers_cond, &e->m_observers_lock);
 | 
			
		||||
 | 
			
		||||
    /* Don't block internal status triggers. */
 | 
			
		||||
    uint32_t old, new;
 | 
			
		||||
    do {
 | 
			
		||||
      old = ddsrt_atomic_ld32 (&e->m_status.m_status_and_mask);
 | 
			
		||||
| 
						 | 
				
			
			@ -910,7 +1031,7 @@ dds_return_t dds_set_status_mask (dds_entity_t entity, uint32_t mask)
 | 
			
		|||
    } while (!ddsrt_atomic_cas32 (&e->m_status.m_status_and_mask, old, new));
 | 
			
		||||
    ddsrt_mutex_unlock (&e->m_observers_lock);
 | 
			
		||||
  }
 | 
			
		||||
  dds_entity_unpin (e);
 | 
			
		||||
  dds_entity_unlock (e);
 | 
			
		||||
  return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -946,7 +1067,6 @@ static dds_return_t dds_readtake_status (dds_entity_t entity, uint32_t *status,
 | 
			
		|||
  return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
dds_return_t dds_read_status (dds_entity_t entity, uint32_t *status, uint32_t mask)
 | 
			
		||||
{
 | 
			
		||||
  return dds_readtake_status (entity, status, mask, false);
 | 
			
		||||
| 
						 | 
				
			
			@ -965,11 +1085,11 @@ dds_return_t dds_get_domainid (dds_entity_t entity, dds_domainid_t *id)
 | 
			
		|||
  if (id == NULL)
 | 
			
		||||
    return DDS_RETCODE_BAD_PARAMETER;
 | 
			
		||||
 | 
			
		||||
  if ((rc = dds_entity_lock (entity, DDS_KIND_DONTCARE, &e)) != DDS_RETCODE_OK)
 | 
			
		||||
  if ((rc = dds_entity_pin (entity, &e)) != DDS_RETCODE_OK)
 | 
			
		||||
    return rc;
 | 
			
		||||
 | 
			
		||||
  *id = e->m_domain->m_id;
 | 
			
		||||
  dds_entity_unlock(e);
 | 
			
		||||
  *id = e->m_domain ? e->m_domain->m_id : DDS_DOMAIN_DEFAULT;
 | 
			
		||||
  dds_entity_unpin (e);
 | 
			
		||||
  return DDS_RETCODE_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1029,7 +1149,7 @@ dds_return_t dds_entity_lock (dds_entity_t hdl, dds_entity_kind_t kind, dds_enti
 | 
			
		|||
void dds_entity_unlock (dds_entity *e)
 | 
			
		||||
{
 | 
			
		||||
  ddsrt_mutex_unlock (&e->m_mutex);
 | 
			
		||||
  dds_handle_unpin (&e->m_hdllink);
 | 
			
		||||
  dds_entity_unpin (e);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dds_return_t dds_triggered (dds_entity_t entity)
 | 
			
		||||
| 
						 | 
				
			
			@ -1047,7 +1167,7 @@ dds_return_t dds_triggered (dds_entity_t entity)
 | 
			
		|||
  return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool in_observer_list_p (const struct dds_entity *observed, const dds_entity *observer)
 | 
			
		||||
static bool in_observer_list_p (const struct dds_entity *observed, const dds_waitset *observer)
 | 
			
		||||
{
 | 
			
		||||
  dds_entity_observer *cur;
 | 
			
		||||
  for (cur = observed->m_observers; cur != NULL; cur = cur->m_next)
 | 
			
		||||
| 
						 | 
				
			
			@ -1056,13 +1176,15 @@ static bool in_observer_list_p (const struct dds_entity *observed, const dds_ent
 | 
			
		|||
  return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dds_return_t dds_entity_observer_register (dds_entity *observed, dds_entity *observer, dds_entity_callback cb, dds_entity_delete_callback delete_cb)
 | 
			
		||||
dds_return_t dds_entity_observer_register (dds_entity *observed, dds_waitset *observer, dds_entity_callback_t cb, dds_entity_attach_callback_t attach_cb, void *attach_arg, dds_entity_delete_callback_t delete_cb)
 | 
			
		||||
{
 | 
			
		||||
  dds_return_t rc;
 | 
			
		||||
  assert (observed);
 | 
			
		||||
  ddsrt_mutex_lock (&observed->m_observers_lock);
 | 
			
		||||
  if (in_observer_list_p (observed, observer))
 | 
			
		||||
    rc = DDS_RETCODE_PRECONDITION_NOT_MET;
 | 
			
		||||
  else if (!attach_cb (observer, observed, attach_arg))
 | 
			
		||||
    rc = DDS_RETCODE_BAD_PARAMETER;
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
    dds_entity_observer *o = ddsrt_malloc (sizeof (dds_entity_observer));
 | 
			
		||||
| 
						 | 
				
			
			@ -1077,7 +1199,7 @@ dds_return_t dds_entity_observer_register (dds_entity *observed, dds_entity *obs
 | 
			
		|||
  return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dds_return_t dds_entity_observer_unregister (dds_entity *observed, dds_entity *observer)
 | 
			
		||||
dds_return_t dds_entity_observer_unregister (dds_entity *observed, dds_waitset *observer, bool invoke_delete_cb)
 | 
			
		||||
{
 | 
			
		||||
  dds_return_t rc;
 | 
			
		||||
  dds_entity_observer *prev, *idx;
 | 
			
		||||
| 
						 | 
				
			
			@ -1098,6 +1220,8 @@ dds_return_t dds_entity_observer_unregister (dds_entity *observed, dds_entity *o
 | 
			
		|||
      observed->m_observers = idx->m_next;
 | 
			
		||||
    else
 | 
			
		||||
      prev->m_next = idx->m_next;
 | 
			
		||||
    if (invoke_delete_cb)
 | 
			
		||||
      idx->m_delete_cb (idx->m_observer, observed->m_hdllink.hdl);
 | 
			
		||||
    ddsrt_free (idx);
 | 
			
		||||
    rc = DDS_RETCODE_OK;
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -1105,21 +1229,6 @@ dds_return_t dds_entity_observer_unregister (dds_entity *observed, dds_entity *o
 | 
			
		|||
  return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void dds_entity_observers_delete (dds_entity *observed)
 | 
			
		||||
{
 | 
			
		||||
  dds_entity_observer *idx;
 | 
			
		||||
  ddsrt_mutex_lock (&observed->m_observers_lock);
 | 
			
		||||
  idx = observed->m_observers;
 | 
			
		||||
  while (idx != NULL)
 | 
			
		||||
  {
 | 
			
		||||
    dds_entity_observer *next = idx->m_next;
 | 
			
		||||
    ddsrt_free (idx);
 | 
			
		||||
    idx = next;
 | 
			
		||||
  }
 | 
			
		||||
  observed->m_observers = NULL;
 | 
			
		||||
  ddsrt_mutex_unlock (&observed->m_observers_lock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void dds_entity_observers_signal (dds_entity *observed, uint32_t status)
 | 
			
		||||
{
 | 
			
		||||
  for (dds_entity_observer *idx = observed->m_observers; idx; idx = idx->m_next)
 | 
			
		||||
| 
						 | 
				
			
			@ -1128,8 +1237,16 @@ static void dds_entity_observers_signal (dds_entity *observed, uint32_t status)
 | 
			
		|||
 | 
			
		||||
static void dds_entity_observers_signal_delete (dds_entity *observed)
 | 
			
		||||
{
 | 
			
		||||
  for (dds_entity_observer *idx = observed->m_observers; idx; idx = idx->m_next)
 | 
			
		||||
  dds_entity_observer *idx;
 | 
			
		||||
  idx = observed->m_observers;
 | 
			
		||||
  while (idx != NULL)
 | 
			
		||||
  {
 | 
			
		||||
    dds_entity_observer *next = idx->m_next;
 | 
			
		||||
    idx->m_delete_cb (idx->m_observer, observed->m_hdllink.hdl);
 | 
			
		||||
    ddsrt_free (idx);
 | 
			
		||||
    idx = next;
 | 
			
		||||
  }
 | 
			
		||||
  observed->m_observers = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dds_entity_status_signal (dds_entity *e, uint32_t status)
 | 
			
		||||
| 
						 | 
				
			
			@ -1158,11 +1275,13 @@ void dds_entity_trigger_set (dds_entity *e, uint32_t t)
 | 
			
		|||
{
 | 
			
		||||
  assert (! entity_has_status (e));
 | 
			
		||||
  uint32_t oldst;
 | 
			
		||||
  ddsrt_mutex_lock (&e->m_observers_lock);
 | 
			
		||||
  do {
 | 
			
		||||
    oldst = ddsrt_atomic_ld32 (&e->m_status.m_trigger);
 | 
			
		||||
  } while (!ddsrt_atomic_cas32 (&e->m_status.m_trigger, oldst, t));
 | 
			
		||||
  if (oldst == 0 && t != 0)
 | 
			
		||||
    dds_entity_observers_signal (e, t);
 | 
			
		||||
  ddsrt_mutex_unlock (&e->m_observers_lock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dds_entity_t dds_get_topic (dds_entity_t entity)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,6 +11,7 @@
 | 
			
		|||
 */
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include "dds__init.h"
 | 
			
		||||
#include "dds__reader.h"
 | 
			
		||||
#include "dds__guardcond.h"
 | 
			
		||||
#include "dds__participant.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -22,28 +23,53 @@
 | 
			
		|||
DECL_ENTITY_LOCK_UNLOCK (extern inline, dds_guardcond)
 | 
			
		||||
 | 
			
		||||
const struct dds_entity_deriver dds_entity_deriver_guardcondition = {
 | 
			
		||||
  .interrupt = dds_entity_deriver_dummy_interrupt,
 | 
			
		||||
  .close = dds_entity_deriver_dummy_close,
 | 
			
		||||
  .delete = dds_entity_deriver_dummy_delete,
 | 
			
		||||
  .set_qos = dds_entity_deriver_dummy_set_qos,
 | 
			
		||||
  .validate_status = dds_entity_deriver_dummy_validate_status
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
dds_entity_t dds_create_guardcondition (dds_entity_t participant)
 | 
			
		||||
dds_entity_t dds_create_guardcondition (dds_entity_t owner)
 | 
			
		||||
{
 | 
			
		||||
  dds_participant *pp;
 | 
			
		||||
  dds_entity *e;
 | 
			
		||||
  dds_return_t rc;
 | 
			
		||||
 | 
			
		||||
  if ((rc = dds_participant_lock (participant, &pp)) != DDS_RETCODE_OK)
 | 
			
		||||
  /* If the owner is any ordinary (allowed) entity, the library is already initialised and calling
 | 
			
		||||
     init here is cheap.  If it is DDS_CYCLONEDDS_HANDLE, we may have to initialise the library, so
 | 
			
		||||
     have to call it.  If it is some bogus value and the library is not initialised yet ... so be
 | 
			
		||||
     it.  Naturally, this requires us to call delete on DDS_CYCLONEDDS_HANDLE afterward. */
 | 
			
		||||
  if ((rc = dds_init ()) < 0)
 | 
			
		||||
    return rc;
 | 
			
		||||
  else
 | 
			
		||||
 | 
			
		||||
  if ((rc = dds_entity_lock (owner, DDS_KIND_DONTCARE, &e)) != DDS_RETCODE_OK)
 | 
			
		||||
    goto err_entity_lock;
 | 
			
		||||
 | 
			
		||||
  switch (dds_entity_kind (e))
 | 
			
		||||
  {
 | 
			
		||||
    dds_guardcond *gcond = dds_alloc (sizeof (*gcond));
 | 
			
		||||
    dds_entity_t hdl = dds_entity_init (&gcond->m_entity, &pp->m_entity, DDS_KIND_COND_GUARD, NULL, NULL, 0);
 | 
			
		||||
    gcond->m_entity.m_iid = ddsi_iid_gen ();
 | 
			
		||||
    dds_entity_register_child (&pp->m_entity, &gcond->m_entity);
 | 
			
		||||
    dds_participant_unlock (pp);
 | 
			
		||||
    return hdl;
 | 
			
		||||
    case DDS_KIND_CYCLONEDDS:
 | 
			
		||||
    case DDS_KIND_DOMAIN:
 | 
			
		||||
    case DDS_KIND_PARTICIPANT:
 | 
			
		||||
      break;
 | 
			
		||||
    default:
 | 
			
		||||
      rc = DDS_RETCODE_ILLEGAL_OPERATION;
 | 
			
		||||
      goto err_entity_kind;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  dds_guardcond *gcond = dds_alloc (sizeof (*gcond));
 | 
			
		||||
  dds_entity_t hdl = dds_entity_init (&gcond->m_entity, e, DDS_KIND_COND_GUARD, NULL, NULL, 0);
 | 
			
		||||
  gcond->m_entity.m_iid = ddsi_iid_gen ();
 | 
			
		||||
  dds_entity_register_child (e, &gcond->m_entity);
 | 
			
		||||
  dds_entity_init_complete (&gcond->m_entity);
 | 
			
		||||
  dds_entity_unlock (e);
 | 
			
		||||
  dds_delete_impl_pinned (&dds_global.m_entity, DIS_EXPLICIT);
 | 
			
		||||
  return hdl;
 | 
			
		||||
 | 
			
		||||
 err_entity_kind:
 | 
			
		||||
  dds_entity_unlock (e);
 | 
			
		||||
 err_entity_lock:
 | 
			
		||||
  dds_delete_impl_pinned (&dds_global.m_entity, DIS_EXPLICIT);
 | 
			
		||||
  return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dds_return_t dds_set_guardcondition (dds_entity_t condition, bool triggered)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,27 +20,10 @@
 | 
			
		|||
#include "dds__handles.h"
 | 
			
		||||
#include "dds__types.h"
 | 
			
		||||
 | 
			
		||||
/* FIXME: this code isn't really correct when USE_CHH is set:
 | 
			
		||||
   - the DDS entity code doesn't really play by the awake/asleep mechanism
 | 
			
		||||
   - there is no provision in the code for a handle being deleted concurrent to a lookup,
 | 
			
		||||
     that is, deleting handle links should also go through the GC
 | 
			
		||||
   entity framework needs a fair bit of rewriting anyway ... */
 | 
			
		||||
#define USE_CHH 0
 | 
			
		||||
 | 
			
		||||
#define HDL_FLAG_CLOSED    (0x80000000u)
 | 
			
		||||
 | 
			
		||||
/* ref count: # outstanding references to this handle/object (not so sure it is
 | 
			
		||||
   ideal to have a one-to-one mapping between the two, but that is what the rest
 | 
			
		||||
   of the code assumes at the moment); so this limits one to having, e.g., no
 | 
			
		||||
   more than 64k endpoints referencing the same topic */
 | 
			
		||||
#define HDL_REFCOUNT_MASK  (0x0ffff000u)
 | 
			
		||||
#define HDL_REFCOUNT_UNIT  (0x00001000u)
 | 
			
		||||
#define HDL_REFCOUNT_SHIFT 12
 | 
			
		||||
 | 
			
		||||
/* pin count: # concurrent operations, so allowing up to 4096 threads had better
 | 
			
		||||
   be enough ... */
 | 
			
		||||
#define HDL_PINCOUNT_MASK  (0x00000fffu)
 | 
			
		||||
#define HDL_PINCOUNT_UNIT  (0x00000001u)
 | 
			
		||||
 | 
			
		||||
/* Maximum number of handles is INT32_MAX - 1, but as the allocator relies on a
 | 
			
		||||
   random generator for finding a free one, the time spent in the dds_handle_create
 | 
			
		||||
| 
						 | 
				
			
			@ -50,11 +33,7 @@
 | 
			
		|||
#define MAX_HANDLES (INT32_MAX / 128)
 | 
			
		||||
 | 
			
		||||
struct dds_handle_server {
 | 
			
		||||
#if USE_CHH
 | 
			
		||||
  struct ddsrt_chh *ht;
 | 
			
		||||
#else
 | 
			
		||||
  struct ddsrt_hh *ht;
 | 
			
		||||
#endif
 | 
			
		||||
  size_t count;
 | 
			
		||||
  ddsrt_mutex_t lock;
 | 
			
		||||
  ddsrt_cond_t cond;
 | 
			
		||||
| 
						 | 
				
			
			@ -78,45 +57,46 @@ static int handle_equal (const void *va, const void *vb)
 | 
			
		|||
 | 
			
		||||
dds_return_t dds_handle_server_init (void)
 | 
			
		||||
{
 | 
			
		||||
#if USE_CHH
 | 
			
		||||
  handles.ht = ddsrt_chh_new (128, handle_hash, handle_equal, free_via_gc);
 | 
			
		||||
#else
 | 
			
		||||
  handles.ht = ddsrt_hh_new (128, handle_hash, handle_equal);
 | 
			
		||||
#endif
 | 
			
		||||
  handles.count = 0;
 | 
			
		||||
  ddsrt_mutex_init (&handles.lock);
 | 
			
		||||
  ddsrt_cond_init (&handles.cond);
 | 
			
		||||
  /* called with ddsrt's singleton mutex held (see dds_init/fini) */
 | 
			
		||||
  if (handles.ht == NULL)
 | 
			
		||||
  {
 | 
			
		||||
    handles.ht = ddsrt_hh_new (128, handle_hash, handle_equal);
 | 
			
		||||
    handles.count = 0;
 | 
			
		||||
    ddsrt_mutex_init (&handles.lock);
 | 
			
		||||
    ddsrt_cond_init (&handles.cond);
 | 
			
		||||
  }
 | 
			
		||||
  return DDS_RETCODE_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dds_handle_server_fini (void)
 | 
			
		||||
{
 | 
			
		||||
#if USE_CHH
 | 
			
		||||
  /* called with ddsrt's singleton mutex held (see dds_init/fini) */
 | 
			
		||||
  if (handles.ht != NULL)
 | 
			
		||||
  {
 | 
			
		||||
#ifndef NDEBUG
 | 
			
		||||
  struct ddsrt_chh_iter it;
 | 
			
		||||
  assert (ddsrt_chh_iter_first (handles.ht, &it) == NULL);
 | 
			
		||||
    struct ddsrt_hh_iter it;
 | 
			
		||||
    for (struct dds_handle_link *link = ddsrt_hh_iter_first (handles.ht, &it); link != NULL; link = ddsrt_hh_iter_next (&it))
 | 
			
		||||
    {
 | 
			
		||||
      uint32_t cf = ddsrt_atomic_ld32 (&link->cnt_flags);
 | 
			
		||||
      DDS_ERROR ("handle %"PRId32" pin %"PRIu32" refc %"PRIu32"%s%s%s\n", link->hdl,
 | 
			
		||||
                 cf & HDL_PINCOUNT_MASK, (cf & HDL_REFCOUNT_MASK) >> HDL_REFCOUNT_SHIFT,
 | 
			
		||||
                 cf & HDL_FLAG_PENDING ? " pending" : "",
 | 
			
		||||
                 cf & HDL_FLAG_CLOSING ? " closing" : "",
 | 
			
		||||
                 cf & HDL_FLAG_CLOSED ? " closed" : "");
 | 
			
		||||
    }
 | 
			
		||||
    assert (ddsrt_hh_iter_first (handles.ht, &it) == NULL);
 | 
			
		||||
#endif
 | 
			
		||||
  ddsrt_chh_free (handles.ht);
 | 
			
		||||
#else /* USE_CHH */
 | 
			
		||||
#ifndef NDEBUG
 | 
			
		||||
  struct ddsrt_hh_iter it;
 | 
			
		||||
  assert (ddsrt_hh_iter_first (handles.ht, &it) == NULL);
 | 
			
		||||
#endif
 | 
			
		||||
  ddsrt_hh_free (handles.ht);
 | 
			
		||||
#endif /* USE_CHH */
 | 
			
		||||
  ddsrt_cond_destroy (&handles.cond);
 | 
			
		||||
  ddsrt_mutex_destroy (&handles.lock);
 | 
			
		||||
  handles.ht = NULL;
 | 
			
		||||
    ddsrt_hh_free (handles.ht);
 | 
			
		||||
    ddsrt_cond_destroy (&handles.cond);
 | 
			
		||||
    ddsrt_mutex_destroy (&handles.lock);
 | 
			
		||||
    handles.ht = NULL;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if USE_CHH
 | 
			
		||||
static bool hhadd (struct ddsrt_chh *ht, void *elem) { return ddsrt_chh_add (ht, elem); }
 | 
			
		||||
#else
 | 
			
		||||
static bool hhadd (struct ddsrt_hh *ht, void *elem) { return ddsrt_hh_add (ht, elem); }
 | 
			
		||||
#endif
 | 
			
		||||
static dds_handle_t dds_handle_create_int (struct dds_handle_link *link)
 | 
			
		||||
{
 | 
			
		||||
  ddsrt_atomic_st32 (&link->cnt_flags, HDL_REFCOUNT_UNIT);
 | 
			
		||||
  ddsrt_atomic_st32 (&link->cnt_flags, HDL_FLAG_PENDING | HDL_REFCOUNT_UNIT | 1u);
 | 
			
		||||
  do {
 | 
			
		||||
    do {
 | 
			
		||||
      link->hdl = (int32_t) (ddsrt_random () & INT32_MAX);
 | 
			
		||||
| 
						 | 
				
			
			@ -127,13 +107,7 @@ static dds_handle_t dds_handle_create_int (struct dds_handle_link *link)
 | 
			
		|||
 | 
			
		||||
dds_handle_t dds_handle_create (struct dds_handle_link *link)
 | 
			
		||||
{
 | 
			
		||||
#if USE_CHH
 | 
			
		||||
  struct thread_state1 * const ts1 = lookup_thread_state ();
 | 
			
		||||
#endif
 | 
			
		||||
  dds_handle_t ret;
 | 
			
		||||
#if USE_CHH
 | 
			
		||||
  thread_state_awake (ts1);
 | 
			
		||||
#endif
 | 
			
		||||
  ddsrt_mutex_lock (&handles.lock);
 | 
			
		||||
  if (handles.count == MAX_HANDLES)
 | 
			
		||||
  {
 | 
			
		||||
| 
						 | 
				
			
			@ -143,55 +117,67 @@ dds_handle_t dds_handle_create (struct dds_handle_link *link)
 | 
			
		|||
  else
 | 
			
		||||
  {
 | 
			
		||||
    handles.count++;
 | 
			
		||||
#if USE_CHH
 | 
			
		||||
    ddsrt_mutex_unlock (&handles.lock);
 | 
			
		||||
    ret = dds_handle_create_int (link);
 | 
			
		||||
#else
 | 
			
		||||
    ret = dds_handle_create_int (link);
 | 
			
		||||
    ddsrt_mutex_unlock (&handles.lock);
 | 
			
		||||
#endif
 | 
			
		||||
    assert (ret > 0);
 | 
			
		||||
  }
 | 
			
		||||
#if USE_CHH
 | 
			
		||||
  thread_state_asleep (ts1);
 | 
			
		||||
#endif
 | 
			
		||||
  return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dds_handle_close (struct dds_handle_link *link)
 | 
			
		||||
dds_return_t dds_handle_register_special (struct dds_handle_link *link, dds_handle_t handle)
 | 
			
		||||
{
 | 
			
		||||
  ddsrt_atomic_or32 (&link->cnt_flags, HDL_FLAG_CLOSED);
 | 
			
		||||
  dds_return_t ret;
 | 
			
		||||
  if (handle <= 0)
 | 
			
		||||
    return DDS_RETCODE_BAD_PARAMETER;
 | 
			
		||||
  ddsrt_mutex_lock (&handles.lock);
 | 
			
		||||
  if (handles.count == MAX_HANDLES)
 | 
			
		||||
  {
 | 
			
		||||
    ddsrt_mutex_unlock (&handles.lock);
 | 
			
		||||
    ret = DDS_RETCODE_OUT_OF_RESOURCES;
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
    handles.count++;
 | 
			
		||||
    ddsrt_atomic_st32 (&link->cnt_flags, HDL_FLAG_PENDING | HDL_REFCOUNT_UNIT | 1u);
 | 
			
		||||
    link->hdl = handle;
 | 
			
		||||
    if (hhadd (handles.ht, link))
 | 
			
		||||
      ret = handle;
 | 
			
		||||
    else
 | 
			
		||||
      ret = DDS_RETCODE_BAD_PARAMETER;
 | 
			
		||||
    ddsrt_mutex_unlock (&handles.lock);
 | 
			
		||||
    assert (ret > 0);
 | 
			
		||||
  }
 | 
			
		||||
  return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int32_t dds_handle_delete (struct dds_handle_link *link, dds_duration_t timeout)
 | 
			
		||||
void dds_handle_unpend (struct dds_handle_link *link)
 | 
			
		||||
{
 | 
			
		||||
#if USE_CHH
 | 
			
		||||
  struct thread_state1 * const ts1 = lookup_thread_state ();
 | 
			
		||||
#ifndef NDEBUG
 | 
			
		||||
  uint32_t cf = ddsrt_atomic_ld32 (&link->cnt_flags);
 | 
			
		||||
  assert ((cf & HDL_FLAG_PENDING));
 | 
			
		||||
  assert (!(cf & HDL_FLAG_CLOSED));
 | 
			
		||||
  assert (!(cf & HDL_FLAG_CLOSING));
 | 
			
		||||
  assert ((cf & HDL_REFCOUNT_MASK) >= HDL_REFCOUNT_UNIT);
 | 
			
		||||
  assert ((cf & HDL_PINCOUNT_MASK) >= 1u);
 | 
			
		||||
#endif
 | 
			
		||||
  assert (ddsrt_atomic_ld32 (&link->cnt_flags) & HDL_FLAG_CLOSED);
 | 
			
		||||
  ddsrt_mutex_lock (&handles.lock);
 | 
			
		||||
  if ((ddsrt_atomic_ld32 (&link->cnt_flags) & HDL_PINCOUNT_MASK) != 0)
 | 
			
		||||
  ddsrt_atomic_and32 (&link->cnt_flags, ~HDL_FLAG_PENDING);
 | 
			
		||||
  dds_handle_unpin (link);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int32_t dds_handle_delete (struct dds_handle_link *link)
 | 
			
		||||
{
 | 
			
		||||
#ifndef NDEBUG
 | 
			
		||||
  uint32_t cf = ddsrt_atomic_ld32 (&link->cnt_flags);
 | 
			
		||||
  if (!(cf & HDL_FLAG_PENDING))
 | 
			
		||||
  {
 | 
			
		||||
    /* FIXME: there is no sensible solution when this times out, so it must
 | 
			
		||||
       never do that ... */
 | 
			
		||||
    const dds_time_t abstimeout = dds_time () + timeout;
 | 
			
		||||
    while ((ddsrt_atomic_ld32 (&link->cnt_flags) & HDL_PINCOUNT_MASK) != 0)
 | 
			
		||||
    {
 | 
			
		||||
      if (!ddsrt_cond_waituntil (&handles.cond, &handles.lock, abstimeout))
 | 
			
		||||
      {
 | 
			
		||||
        ddsrt_mutex_unlock (&handles.lock);
 | 
			
		||||
        fprintf (stderr, "** timeout in handle_delete **\n");
 | 
			
		||||
        return DDS_RETCODE_TIMEOUT;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    assert (cf & HDL_FLAG_CLOSING);
 | 
			
		||||
    assert (cf & HDL_FLAG_CLOSED);
 | 
			
		||||
    assert ((cf & HDL_REFCOUNT_MASK) == 0u);
 | 
			
		||||
  }
 | 
			
		||||
#if USE_CHH
 | 
			
		||||
  thread_state_awake (ts1);
 | 
			
		||||
  int x = ddsrt_chh_remove (handles.ht, link);
 | 
			
		||||
  thread_state_asleep (ts1);
 | 
			
		||||
#else
 | 
			
		||||
  int x = ddsrt_hh_remove (handles.ht, link);
 | 
			
		||||
  assert ((cf & HDL_PINCOUNT_MASK) == 1u);
 | 
			
		||||
#endif
 | 
			
		||||
  ddsrt_mutex_lock (&handles.lock);
 | 
			
		||||
  int x = ddsrt_hh_remove (handles.ht, link);
 | 
			
		||||
  assert(x);
 | 
			
		||||
  (void)x;
 | 
			
		||||
  assert (handles.count > 0);
 | 
			
		||||
| 
						 | 
				
			
			@ -200,11 +186,8 @@ int32_t dds_handle_delete (struct dds_handle_link *link, dds_duration_t timeout)
 | 
			
		|||
  return DDS_RETCODE_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int32_t dds_handle_pin (dds_handle_t hdl, struct dds_handle_link **link)
 | 
			
		||||
static int32_t dds_handle_pin_int (dds_handle_t hdl, uint32_t delta, struct dds_handle_link **link)
 | 
			
		||||
{
 | 
			
		||||
#if USE_CHH
 | 
			
		||||
  struct thread_state1 * const ts1 = lookup_thread_state ();
 | 
			
		||||
#endif
 | 
			
		||||
  struct dds_handle_link dummy = { .hdl = hdl };
 | 
			
		||||
  int32_t rc;
 | 
			
		||||
  /* it makes sense to check here for initialization: the first thing any operation
 | 
			
		||||
| 
						 | 
				
			
			@ -218,41 +201,41 @@ int32_t dds_handle_pin (dds_handle_t hdl, struct dds_handle_link **link)
 | 
			
		|||
  if (handles.ht == NULL)
 | 
			
		||||
    return DDS_RETCODE_PRECONDITION_NOT_MET;
 | 
			
		||||
 | 
			
		||||
#if USE_CHH
 | 
			
		||||
  thread_state_awake (ts1);
 | 
			
		||||
  *link = ddsrt_chh_lookup (handles.ht, &dummy);
 | 
			
		||||
#else
 | 
			
		||||
  ddsrt_mutex_lock (&handles.lock);
 | 
			
		||||
  *link = ddsrt_hh_lookup (handles.ht, &dummy);
 | 
			
		||||
#endif
 | 
			
		||||
  if (*link == NULL)
 | 
			
		||||
    rc = DDS_RETCODE_BAD_PARAMETER;
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
    uint32_t cnt_flags;
 | 
			
		||||
    uint32_t cf;
 | 
			
		||||
    /* Assume success; bail out if the object turns out to be in the process of
 | 
			
		||||
       being deleted */
 | 
			
		||||
    rc = DDS_RETCODE_OK;
 | 
			
		||||
    do {
 | 
			
		||||
      cnt_flags = ddsrt_atomic_ld32 (&(*link)->cnt_flags);
 | 
			
		||||
      if (cnt_flags & HDL_FLAG_CLOSED)
 | 
			
		||||
      cf = ddsrt_atomic_ld32 (&(*link)->cnt_flags);
 | 
			
		||||
      if (cf & (HDL_FLAG_CLOSED | HDL_FLAG_CLOSING | HDL_FLAG_PENDING))
 | 
			
		||||
      {
 | 
			
		||||
        rc = DDS_RETCODE_BAD_PARAMETER;
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
    } while (!ddsrt_atomic_cas32 (&(*link)->cnt_flags, cnt_flags, cnt_flags + HDL_PINCOUNT_UNIT));
 | 
			
		||||
    } while (!ddsrt_atomic_cas32 (&(*link)->cnt_flags, cf, cf + delta));
 | 
			
		||||
  }
 | 
			
		||||
#if USE_CHH
 | 
			
		||||
  thread_state_asleep (ts1);
 | 
			
		||||
#else
 | 
			
		||||
  ddsrt_mutex_unlock (&handles.lock);
 | 
			
		||||
#endif
 | 
			
		||||
  return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int32_t dds_handle_pin (dds_handle_t hdl, struct dds_handle_link **link)
 | 
			
		||||
{
 | 
			
		||||
  return dds_handle_pin_int (hdl, 1u, link);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int32_t dds_handle_pin_and_ref (dds_handle_t hdl, struct dds_handle_link **link)
 | 
			
		||||
{
 | 
			
		||||
  return dds_handle_pin_int (hdl, HDL_REFCOUNT_UNIT + 1u, link);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dds_handle_repin (struct dds_handle_link *link)
 | 
			
		||||
{
 | 
			
		||||
  DDSRT_STATIC_ASSERT (HDL_PINCOUNT_UNIT == 1);
 | 
			
		||||
  uint32_t x = ddsrt_atomic_inc32_nv (&link->cnt_flags);
 | 
			
		||||
  assert (!(x & HDL_FLAG_CLOSED));
 | 
			
		||||
  (void) x;
 | 
			
		||||
| 
						 | 
				
			
			@ -260,13 +243,20 @@ void dds_handle_repin (struct dds_handle_link *link)
 | 
			
		|||
 | 
			
		||||
void dds_handle_unpin (struct dds_handle_link *link)
 | 
			
		||||
{
 | 
			
		||||
  DDSRT_STATIC_ASSERT (HDL_PINCOUNT_UNIT == 1);
 | 
			
		||||
  if ((ddsrt_atomic_dec32_ov (&link->cnt_flags) & (HDL_FLAG_CLOSED | HDL_PINCOUNT_MASK)) == (HDL_FLAG_CLOSED | HDL_PINCOUNT_UNIT))
 | 
			
		||||
#ifndef NDEBUG
 | 
			
		||||
  uint32_t cf = ddsrt_atomic_ld32 (&link->cnt_flags);
 | 
			
		||||
  assert (!(cf & HDL_FLAG_CLOSED));
 | 
			
		||||
  if (cf & HDL_FLAG_CLOSING)
 | 
			
		||||
    assert ((cf & HDL_PINCOUNT_MASK) > 1u);
 | 
			
		||||
  else
 | 
			
		||||
    assert ((cf & HDL_PINCOUNT_MASK) >= 1u);
 | 
			
		||||
#endif
 | 
			
		||||
  ddsrt_mutex_lock (&handles.lock);
 | 
			
		||||
  if ((ddsrt_atomic_dec32_nv (&link->cnt_flags) & (HDL_FLAG_CLOSING | HDL_PINCOUNT_MASK)) == (HDL_FLAG_CLOSING | 1u))
 | 
			
		||||
  {
 | 
			
		||||
    ddsrt_mutex_lock (&handles.lock);
 | 
			
		||||
    ddsrt_cond_broadcast (&handles.cond);
 | 
			
		||||
    ddsrt_mutex_unlock (&handles.lock);
 | 
			
		||||
  }
 | 
			
		||||
  ddsrt_mutex_unlock (&handles.lock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dds_handle_add_ref (struct dds_handle_link *link)
 | 
			
		||||
| 
						 | 
				
			
			@ -283,12 +273,27 @@ bool dds_handle_drop_ref (struct dds_handle_link *link)
 | 
			
		|||
    if ((old & HDL_REFCOUNT_MASK) != HDL_REFCOUNT_UNIT)
 | 
			
		||||
      new = old - HDL_REFCOUNT_UNIT;
 | 
			
		||||
    else
 | 
			
		||||
      new = (old - HDL_REFCOUNT_UNIT) | HDL_FLAG_CLOSED;
 | 
			
		||||
      new = (old - HDL_REFCOUNT_UNIT) | HDL_FLAG_CLOSING;
 | 
			
		||||
  } while (!ddsrt_atomic_cas32 (&link->cnt_flags, old, new));
 | 
			
		||||
  return (new & HDL_REFCOUNT_MASK) == 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool dds_handle_is_closed (struct dds_handle_link *link)
 | 
			
		||||
void dds_handle_close_wait (struct dds_handle_link *link)
 | 
			
		||||
{
 | 
			
		||||
  return (ddsrt_atomic_ld32 (&link->cnt_flags) & HDL_FLAG_CLOSED) != 0;
 | 
			
		||||
#ifndef NDEBUG
 | 
			
		||||
  uint32_t cf = ddsrt_atomic_ld32 (&link->cnt_flags);
 | 
			
		||||
  assert ((cf & HDL_FLAG_CLOSING));
 | 
			
		||||
  assert (!(cf & HDL_FLAG_CLOSED));
 | 
			
		||||
  assert ((cf & HDL_REFCOUNT_MASK) == 0u);
 | 
			
		||||
  assert ((cf & HDL_PINCOUNT_MASK) >= 1u);
 | 
			
		||||
#endif
 | 
			
		||||
  ddsrt_mutex_lock (&handles.lock);
 | 
			
		||||
  while ((ddsrt_atomic_ld32 (&link->cnt_flags) & HDL_PINCOUNT_MASK) != 1u)
 | 
			
		||||
    ddsrt_cond_wait (&handles.cond, &handles.lock);
 | 
			
		||||
  /* only one thread may call close_wait on a given handle */
 | 
			
		||||
  assert (!(ddsrt_atomic_ld32 (&link->cnt_flags) & HDL_FLAG_CLOSED));
 | 
			
		||||
  ddsrt_atomic_or32 (&link->cnt_flags, HDL_FLAG_CLOSED);
 | 
			
		||||
  ddsrt_mutex_unlock (&handles.lock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
extern inline bool dds_handle_is_closed (struct dds_handle_link *link);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,10 +18,11 @@
 | 
			
		|||
#include "dds/ddsrt/process.h"
 | 
			
		||||
#include "dds/ddsrt/heap.h"
 | 
			
		||||
#include "dds__init.h"
 | 
			
		||||
#include "dds__rhc.h"
 | 
			
		||||
#include "dds/ddsc/dds_rhc.h"
 | 
			
		||||
#include "dds__domain.h"
 | 
			
		||||
#include "dds__builtin.h"
 | 
			
		||||
#include "dds__whc_builtintopic.h"
 | 
			
		||||
#include "dds__entity.h"
 | 
			
		||||
#include "dds/ddsi/ddsi_iid.h"
 | 
			
		||||
#include "dds/ddsi/ddsi_tkmap.h"
 | 
			
		||||
#include "dds/ddsi/ddsi_serdata.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -32,10 +33,49 @@
 | 
			
		|||
#include "dds/ddsi/q_globals.h"
 | 
			
		||||
#include "dds/version.h"
 | 
			
		||||
 | 
			
		||||
#define DOMAIN_ID_MIN 0
 | 
			
		||||
#define DOMAIN_ID_MAX 230
 | 
			
		||||
static void dds_close (struct dds_entity *e);
 | 
			
		||||
static dds_return_t dds_fini (struct dds_entity *e);
 | 
			
		||||
 | 
			
		||||
dds_globals dds_global;
 | 
			
		||||
const struct dds_entity_deriver dds_entity_deriver_cyclonedds = {
 | 
			
		||||
  .interrupt = dds_entity_deriver_dummy_interrupt,
 | 
			
		||||
  .close = dds_close,
 | 
			
		||||
  .delete = dds_fini,
 | 
			
		||||
  .set_qos = dds_entity_deriver_dummy_set_qos,
 | 
			
		||||
  .validate_status = dds_entity_deriver_dummy_validate_status
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
dds_cyclonedds_entity dds_global;
 | 
			
		||||
 | 
			
		||||
#define CDDS_STATE_ZERO 0u
 | 
			
		||||
#define CDDS_STATE_STARTING 1u
 | 
			
		||||
#define CDDS_STATE_READY 2u
 | 
			
		||||
#define CDDS_STATE_STOPPING 3u
 | 
			
		||||
static ddsrt_atomic_uint32_t dds_state = DDSRT_ATOMIC_UINT32_INIT (CDDS_STATE_ZERO);
 | 
			
		||||
 | 
			
		||||
static void common_cleanup (void)
 | 
			
		||||
{
 | 
			
		||||
  if (thread_states_fini ())
 | 
			
		||||
    dds_handle_server_fini ();
 | 
			
		||||
 | 
			
		||||
  ddsi_iid_fini ();
 | 
			
		||||
  ddsrt_cond_destroy (&dds_global.m_cond);
 | 
			
		||||
  ddsrt_mutex_destroy (&dds_global.m_mutex);
 | 
			
		||||
 | 
			
		||||
  ddsrt_atomic_st32 (&dds_state, CDDS_STATE_ZERO);
 | 
			
		||||
  ddsrt_cond_broadcast (ddsrt_get_singleton_cond ());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool cyclonedds_entity_ready (uint32_t s)
 | 
			
		||||
{
 | 
			
		||||
  assert (s != CDDS_STATE_ZERO);
 | 
			
		||||
  if (s == CDDS_STATE_STARTING || s == CDDS_STATE_STOPPING)
 | 
			
		||||
    return false;
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
    struct dds_handle_link *x;
 | 
			
		||||
    return dds_handle_pin_and_ref (DDS_CYCLONEDDS_HANDLE, &x) == DDS_RETCODE_OK;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dds_return_t dds_init (void)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -43,18 +83,34 @@ dds_return_t dds_init (void)
 | 
			
		|||
 | 
			
		||||
  ddsrt_init ();
 | 
			
		||||
  ddsrt_mutex_t * const init_mutex = ddsrt_get_singleton_mutex ();
 | 
			
		||||
  ddsrt_cond_t * const init_cond = ddsrt_get_singleton_cond ();
 | 
			
		||||
 | 
			
		||||
  ddsrt_mutex_lock (init_mutex);
 | 
			
		||||
  if (dds_global.m_init_count++ != 0)
 | 
			
		||||
  uint32_t s = ddsrt_atomic_ld32 (&dds_state);
 | 
			
		||||
  while (s != CDDS_STATE_ZERO && !cyclonedds_entity_ready (s))
 | 
			
		||||
  {
 | 
			
		||||
    ddsrt_mutex_unlock (init_mutex);
 | 
			
		||||
    return DDS_RETCODE_OK;
 | 
			
		||||
    ddsrt_cond_wait (init_cond, init_mutex);
 | 
			
		||||
    s = ddsrt_atomic_ld32 (&dds_state);
 | 
			
		||||
  }
 | 
			
		||||
  switch (s)
 | 
			
		||||
  {
 | 
			
		||||
    case CDDS_STATE_READY:
 | 
			
		||||
      assert (dds_global.m_entity.m_hdllink.hdl == DDS_CYCLONEDDS_HANDLE);
 | 
			
		||||
      ddsrt_mutex_unlock (init_mutex);
 | 
			
		||||
      return DDS_RETCODE_OK;
 | 
			
		||||
    case CDDS_STATE_ZERO:
 | 
			
		||||
      ddsrt_atomic_st32 (&dds_state, CDDS_STATE_STARTING);
 | 
			
		||||
      break;
 | 
			
		||||
    default:
 | 
			
		||||
      ddsrt_mutex_unlock (init_mutex);
 | 
			
		||||
      ddsrt_fini ();
 | 
			
		||||
      return DDS_RETCODE_ERROR;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ddsrt_mutex_init (&dds_global.m_mutex);
 | 
			
		||||
  ddsrt_cond_init (&dds_global.m_cond);
 | 
			
		||||
  ddsi_iid_init ();
 | 
			
		||||
  thread_states_init_static ();
 | 
			
		||||
  thread_states_init (64);
 | 
			
		||||
  upgrade_main_thread ();
 | 
			
		||||
 | 
			
		||||
  if (dds_handle_server_init () != DDS_RETCODE_OK)
 | 
			
		||||
  {
 | 
			
		||||
| 
						 | 
				
			
			@ -63,30 +119,48 @@ dds_return_t dds_init (void)
 | 
			
		|||
    goto fail_handleserver;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  dds_entity_init (&dds_global.m_entity, NULL, DDS_KIND_CYCLONEDDS, NULL, NULL, 0);
 | 
			
		||||
  dds_global.m_entity.m_iid = ddsi_iid_gen ();
 | 
			
		||||
  dds_global.m_entity.m_flags = DDS_ENTITY_IMPLICIT;
 | 
			
		||||
  dds_handle_repin (&dds_global.m_entity.m_hdllink);
 | 
			
		||||
  dds_entity_add_ref_locked (&dds_global.m_entity);
 | 
			
		||||
  dds_entity_init_complete (&dds_global.m_entity);
 | 
			
		||||
  ddsrt_atomic_st32 (&dds_state, CDDS_STATE_READY);
 | 
			
		||||
  ddsrt_mutex_unlock (init_mutex);
 | 
			
		||||
  return DDS_RETCODE_OK;
 | 
			
		||||
 | 
			
		||||
fail_handleserver:
 | 
			
		||||
  ddsrt_mutex_destroy (&dds_global.m_mutex);
 | 
			
		||||
  dds_global.m_init_count--;
 | 
			
		||||
  common_cleanup ();
 | 
			
		||||
  ddsrt_mutex_unlock (init_mutex);
 | 
			
		||||
  ddsrt_fini ();
 | 
			
		||||
  return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
extern void dds_fini (void)
 | 
			
		||||
static void dds_close (struct dds_entity *e)
 | 
			
		||||
{
 | 
			
		||||
  (void) e;
 | 
			
		||||
  assert (ddsrt_atomic_ld32 (&dds_state) == CDDS_STATE_READY);
 | 
			
		||||
  ddsrt_atomic_st32 (&dds_state, CDDS_STATE_STOPPING);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static dds_return_t dds_fini (struct dds_entity *e)
 | 
			
		||||
{
 | 
			
		||||
  (void) e;
 | 
			
		||||
  ddsrt_mutex_t * const init_mutex = ddsrt_get_singleton_mutex ();
 | 
			
		||||
  /* If there are multiple domains shutting down simultaneously, the one "deleting" the top-level
 | 
			
		||||
     entity (and thus arriving here) may have overtaken another thread that is still in the process
 | 
			
		||||
     of deleting its domain object.  For most entities such races are not an issue, but here we tear
 | 
			
		||||
     down the run-time, so here we must wait until everyone else is out. */
 | 
			
		||||
  ddsrt_mutex_lock (&dds_global.m_mutex);
 | 
			
		||||
  while (!ddsrt_avl_is_empty (&dds_global.m_domains))
 | 
			
		||||
    ddsrt_cond_wait (&dds_global.m_cond, &dds_global.m_mutex);
 | 
			
		||||
  ddsrt_mutex_unlock (&dds_global.m_mutex);
 | 
			
		||||
 | 
			
		||||
  ddsrt_mutex_lock (init_mutex);
 | 
			
		||||
  assert (dds_global.m_init_count > 0);
 | 
			
		||||
  if (--dds_global.m_init_count == 0)
 | 
			
		||||
  {
 | 
			
		||||
    dds_handle_server_fini ();
 | 
			
		||||
    downgrade_main_thread ();
 | 
			
		||||
    thread_states_fini ();
 | 
			
		||||
    ddsi_iid_fini ();
 | 
			
		||||
    ddsrt_mutex_destroy (&dds_global.m_mutex);
 | 
			
		||||
  }
 | 
			
		||||
  assert (ddsrt_atomic_ld32 (&dds_state) == CDDS_STATE_STOPPING);
 | 
			
		||||
  dds_entity_final_deinit_before_free (e);
 | 
			
		||||
  common_cleanup ();
 | 
			
		||||
  ddsrt_mutex_unlock (init_mutex);
 | 
			
		||||
  ddsrt_fini ();
 | 
			
		||||
  return DDS_RETCODE_NO_DATA;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,7 +16,7 @@
 | 
			
		|||
#include "dds__entity.h"
 | 
			
		||||
#include "dds__write.h"
 | 
			
		||||
#include "dds__writer.h"
 | 
			
		||||
#include "dds__rhc.h"
 | 
			
		||||
#include "dds/ddsc/dds_rhc.h"
 | 
			
		||||
#include "dds/ddsi/ddsi_tkmap.h"
 | 
			
		||||
#include "dds/ddsi/ddsi_serdata.h"
 | 
			
		||||
#include "dds/ddsi/q_entity.h"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -27,15 +27,14 @@ dds_return_t dds_get_matched_subscriptions (dds_entity_t writer, dds_instance_ha
 | 
			
		|||
{
 | 
			
		||||
  dds_writer *wr;
 | 
			
		||||
  dds_return_t rc;
 | 
			
		||||
  if (rds == NULL && nrds > 0)
 | 
			
		||||
  if ((rds != NULL && (nrds == 0 || nrds > INT32_MAX)) || (rds == NULL && nrds != 0))
 | 
			
		||||
    return DDS_RETCODE_BAD_PARAMETER;
 | 
			
		||||
  if ((rc = dds_writer_lock (writer, &wr)) != DDS_RETCODE_OK)
 | 
			
		||||
    return rc;
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
    const struct ephash *gh = wr->m_entity.m_domain->gv.guid_hash;
 | 
			
		||||
    const int32_t nrds_max = (nrds > INT32_MAX) ? INT32_MAX : (int32_t) nrds;
 | 
			
		||||
    int32_t nrds_act = 0;
 | 
			
		||||
    size_t nrds_act = 0;
 | 
			
		||||
    ddsrt_avl_iter_t it;
 | 
			
		||||
    /* FIXME: this ought not be so tightly coupled to the lower layer */
 | 
			
		||||
    thread_state_awake (lookup_thread_state (), &wr->m_entity.m_domain->gv);
 | 
			
		||||
| 
						 | 
				
			
			@ -47,7 +46,7 @@ dds_return_t dds_get_matched_subscriptions (dds_entity_t writer, dds_instance_ha
 | 
			
		|||
      struct proxy_reader *prd;
 | 
			
		||||
      if ((prd = ephash_lookup_proxy_reader_guid (gh, &m->prd_guid)) != NULL)
 | 
			
		||||
      {
 | 
			
		||||
        if (nrds_act < nrds_max)
 | 
			
		||||
        if (nrds_act < nrds)
 | 
			
		||||
          rds[nrds_act] = prd->e.iid;
 | 
			
		||||
        nrds_act++;
 | 
			
		||||
      }
 | 
			
		||||
| 
						 | 
				
			
			@ -59,7 +58,7 @@ dds_return_t dds_get_matched_subscriptions (dds_entity_t writer, dds_instance_ha
 | 
			
		|||
      struct reader *rd;
 | 
			
		||||
      if ((rd = ephash_lookup_reader_guid (gh, &m->rd_guid)) != NULL)
 | 
			
		||||
      {
 | 
			
		||||
        if (nrds_act < nrds_max)
 | 
			
		||||
        if (nrds_act < nrds)
 | 
			
		||||
          rds[nrds_act] = rd->e.iid;
 | 
			
		||||
        nrds_act++;
 | 
			
		||||
      }
 | 
			
		||||
| 
						 | 
				
			
			@ -67,7 +66,10 @@ dds_return_t dds_get_matched_subscriptions (dds_entity_t writer, dds_instance_ha
 | 
			
		|||
    ddsrt_mutex_unlock (&wr->m_wr->e.lock);
 | 
			
		||||
    thread_state_asleep (lookup_thread_state ());
 | 
			
		||||
    dds_writer_unlock (wr);
 | 
			
		||||
    return nrds_act;
 | 
			
		||||
    /* FIXME: is it really true that there can not be more than INT32_MAX matching readers?
 | 
			
		||||
       (in practice it'll come to a halt long before that) */
 | 
			
		||||
    assert (nrds_act <= INT32_MAX);
 | 
			
		||||
    return (dds_return_t) nrds_act;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -75,15 +77,14 @@ dds_return_t dds_get_matched_publications (dds_entity_t reader, dds_instance_han
 | 
			
		|||
{
 | 
			
		||||
  dds_reader *rd;
 | 
			
		||||
  dds_return_t rc;
 | 
			
		||||
  if (wrs == NULL && nwrs > 0)
 | 
			
		||||
  if ((wrs != NULL && (nwrs == 0 || nwrs > INT32_MAX)) || (wrs == NULL && nwrs != 0))
 | 
			
		||||
    return DDS_RETCODE_BAD_PARAMETER;
 | 
			
		||||
  if ((rc = dds_reader_lock (reader, &rd)) != DDS_RETCODE_OK)
 | 
			
		||||
    return rc;
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
    const struct ephash *gh = rd->m_entity.m_domain->gv.guid_hash;
 | 
			
		||||
    const int32_t nwrs_max = (nwrs > INT32_MAX) ? INT32_MAX : (int32_t) nwrs;
 | 
			
		||||
    int32_t nwrs_act = 0;
 | 
			
		||||
    size_t nwrs_act = 0;
 | 
			
		||||
    ddsrt_avl_iter_t it;
 | 
			
		||||
    /* FIXME: this ought not be so tightly coupled to the lower layer */
 | 
			
		||||
    thread_state_awake (lookup_thread_state (), &rd->m_entity.m_domain->gv);
 | 
			
		||||
| 
						 | 
				
			
			@ -95,7 +96,7 @@ dds_return_t dds_get_matched_publications (dds_entity_t reader, dds_instance_han
 | 
			
		|||
      struct proxy_writer *pwr;
 | 
			
		||||
      if ((pwr = ephash_lookup_proxy_writer_guid (gh, &m->pwr_guid)) != NULL)
 | 
			
		||||
      {
 | 
			
		||||
        if (nwrs_act < nwrs_max)
 | 
			
		||||
        if (nwrs_act < nwrs)
 | 
			
		||||
          wrs[nwrs_act] = pwr->e.iid;
 | 
			
		||||
        nwrs_act++;
 | 
			
		||||
      }
 | 
			
		||||
| 
						 | 
				
			
			@ -107,7 +108,7 @@ dds_return_t dds_get_matched_publications (dds_entity_t reader, dds_instance_han
 | 
			
		|||
      struct writer *wr;
 | 
			
		||||
      if ((wr = ephash_lookup_writer_guid (gh, &m->wr_guid)) != NULL)
 | 
			
		||||
      {
 | 
			
		||||
        if (nwrs_act < nwrs_max)
 | 
			
		||||
        if (nwrs_act < nwrs)
 | 
			
		||||
          wrs[nwrs_act] = wr->e.iid;
 | 
			
		||||
        nwrs_act++;
 | 
			
		||||
      }
 | 
			
		||||
| 
						 | 
				
			
			@ -115,14 +116,17 @@ dds_return_t dds_get_matched_publications (dds_entity_t reader, dds_instance_han
 | 
			
		|||
    ddsrt_mutex_unlock (&rd->m_rd->e.lock);
 | 
			
		||||
    thread_state_asleep (lookup_thread_state ());
 | 
			
		||||
    dds_reader_unlock (rd);
 | 
			
		||||
    return nwrs_act;
 | 
			
		||||
    /* FIXME: is it really true that there can not be more than INT32_MAX matching readers?
 | 
			
		||||
     (in practice it'll come to a halt long before that) */
 | 
			
		||||
    assert (nwrs_act <= INT32_MAX);
 | 
			
		||||
    return (dds_return_t) nwrs_act;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static dds_builtintopic_endpoint_t *make_builtintopic_endpoint (const nn_guid_t *guid, const nn_guid_t *ppguid, dds_instance_handle_t ppiid, const dds_qos_t *qos)
 | 
			
		||||
static dds_builtintopic_endpoint_t *make_builtintopic_endpoint (const ddsi_guid_t *guid, const ddsi_guid_t *ppguid, dds_instance_handle_t ppiid, const dds_qos_t *qos)
 | 
			
		||||
{
 | 
			
		||||
  dds_builtintopic_endpoint_t *ep;
 | 
			
		||||
  nn_guid_t tmp;
 | 
			
		||||
  ddsi_guid_t tmp;
 | 
			
		||||
  ep = dds_alloc (sizeof (*ep));
 | 
			
		||||
  tmp = nn_hton_guid (*guid);
 | 
			
		||||
  memcpy (&ep->key, &tmp, sizeof (ep->key));
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,11 +12,13 @@
 | 
			
		|||
#include <assert.h>
 | 
			
		||||
 | 
			
		||||
#include "dds/ddsrt/cdtors.h"
 | 
			
		||||
#include "dds/ddsrt/environ.h"
 | 
			
		||||
#include "dds/ddsi/q_entity.h"
 | 
			
		||||
#include "dds/ddsi/q_thread.h"
 | 
			
		||||
#include "dds/ddsi/q_config.h"
 | 
			
		||||
#include "dds/ddsi/q_plist.h"
 | 
			
		||||
#include "dds/ddsi/q_globals.h"
 | 
			
		||||
#include "dds/version.h"
 | 
			
		||||
#include "dds__init.h"
 | 
			
		||||
#include "dds__domain.h"
 | 
			
		||||
#include "dds__participant.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -42,14 +44,7 @@ static dds_return_t dds_participant_delete (dds_entity *e)
 | 
			
		|||
  thread_state_awake (lookup_thread_state (), &e->m_domain->gv);
 | 
			
		||||
  if ((ret = delete_participant (&e->m_domain->gv, &e->m_guid)) < 0)
 | 
			
		||||
    DDS_CERROR (&e->m_domain->gv.logconfig, "dds_participant_delete: internal error %"PRId32"\n", ret);
 | 
			
		||||
  ddsrt_mutex_lock (&dds_global.m_mutex);
 | 
			
		||||
  ddsrt_avl_delete (&dds_entity_children_td, &e->m_domain->m_ppants, e);
 | 
			
		||||
  ddsrt_mutex_unlock (&dds_global.m_mutex);
 | 
			
		||||
  thread_state_asleep (lookup_thread_state ());
 | 
			
		||||
 | 
			
		||||
  /* Every dds_init needs a dds_fini. */
 | 
			
		||||
  dds_domain_free (e->m_domain);
 | 
			
		||||
  dds_fini ();
 | 
			
		||||
  return DDS_RETCODE_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -74,6 +69,7 @@ static dds_return_t dds_participant_qos_set (dds_entity *e, const dds_qos_t *qos
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
const struct dds_entity_deriver dds_entity_deriver_participant = {
 | 
			
		||||
  .interrupt = dds_entity_deriver_dummy_interrupt,
 | 
			
		||||
  .close = dds_entity_deriver_dummy_close,
 | 
			
		||||
  .delete = dds_participant_delete,
 | 
			
		||||
  .set_qos = dds_participant_qos_set,
 | 
			
		||||
| 
						 | 
				
			
			@ -84,16 +80,19 @@ dds_entity_t dds_create_participant (const dds_domainid_t domain, const dds_qos_
 | 
			
		|||
{
 | 
			
		||||
  dds_domain *dom;
 | 
			
		||||
  dds_entity_t ret;
 | 
			
		||||
  nn_guid_t guid;
 | 
			
		||||
  ddsi_guid_t guid;
 | 
			
		||||
  dds_participant * pp;
 | 
			
		||||
  nn_plist_t plist;
 | 
			
		||||
  dds_qos_t *new_qos = NULL;
 | 
			
		||||
  char *config = "";
 | 
			
		||||
 | 
			
		||||
  /* Make sure DDS instance is initialized. */
 | 
			
		||||
  if ((ret = dds_init ()) < 0)
 | 
			
		||||
    goto err_dds_init;
 | 
			
		||||
 | 
			
		||||
  if ((ret = dds_domain_create (&dom, domain)) < 0)
 | 
			
		||||
  (void) ddsrt_getenv (DDS_PROJECT_NAME_NOSPACE_CAPS"_URI", &config);
 | 
			
		||||
 | 
			
		||||
  if ((ret = dds_domain_create_internal (&dom, domain, true, config)) < 0)
 | 
			
		||||
    goto err_domain_create;
 | 
			
		||||
 | 
			
		||||
  new_qos = dds_create_qos ();
 | 
			
		||||
| 
						 | 
				
			
			@ -118,7 +117,7 @@ dds_entity_t dds_create_participant (const dds_domainid_t domain, const dds_qos_
 | 
			
		|||
  }
 | 
			
		||||
 | 
			
		||||
  pp = dds_alloc (sizeof (*pp));
 | 
			
		||||
  if ((ret = dds_entity_init (&pp->m_entity, NULL, DDS_KIND_PARTICIPANT, new_qos, listener, DDS_PARTICIPANT_STATUS_MASK)) < 0)
 | 
			
		||||
  if ((ret = dds_entity_init (&pp->m_entity, &dom->m_entity, DDS_KIND_PARTICIPANT, new_qos, listener, DDS_PARTICIPANT_STATUS_MASK)) < 0)
 | 
			
		||||
    goto err_entity_init;
 | 
			
		||||
 | 
			
		||||
  pp->m_entity.m_guid = guid;
 | 
			
		||||
| 
						 | 
				
			
			@ -127,9 +126,14 @@ dds_entity_t dds_create_participant (const dds_domainid_t domain, const dds_qos_
 | 
			
		|||
  pp->m_builtin_subscriber = 0;
 | 
			
		||||
 | 
			
		||||
  /* Add participant to extent */
 | 
			
		||||
  ddsrt_mutex_lock (&dds_global.m_mutex);
 | 
			
		||||
  ddsrt_avl_insert (&dds_entity_children_td, &dom->m_ppants, &pp->m_entity);
 | 
			
		||||
  ddsrt_mutex_unlock (&dds_global.m_mutex);
 | 
			
		||||
  ddsrt_mutex_lock (&dds_global.m_entity.m_mutex);
 | 
			
		||||
  dds_entity_register_child (&dom->m_entity, &pp->m_entity);
 | 
			
		||||
  ddsrt_mutex_unlock (&dds_global.m_entity.m_mutex);
 | 
			
		||||
 | 
			
		||||
  dds_entity_init_complete (&pp->m_entity);
 | 
			
		||||
  /* drop temporary extra ref to domain, dds_init */
 | 
			
		||||
  dds_delete (dom->m_entity.m_hdllink.hdl);
 | 
			
		||||
  dds_delete_impl_pinned (&dds_global.m_entity, DIS_EXPLICIT);
 | 
			
		||||
  return ret;
 | 
			
		||||
 | 
			
		||||
err_entity_init:
 | 
			
		||||
| 
						 | 
				
			
			@ -137,43 +141,40 @@ err_entity_init:
 | 
			
		|||
err_new_participant:
 | 
			
		||||
err_qos_validation:
 | 
			
		||||
  dds_delete_qos (new_qos);
 | 
			
		||||
  dds_domain_free (dom);
 | 
			
		||||
  dds_delete (dom->m_entity.m_hdllink.hdl);
 | 
			
		||||
err_domain_create:
 | 
			
		||||
  dds_fini ();
 | 
			
		||||
  dds_delete_impl_pinned (&dds_global.m_entity, DIS_EXPLICIT);
 | 
			
		||||
err_dds_init:
 | 
			
		||||
  return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dds_entity_t dds_lookup_participant (dds_domainid_t domain_id, dds_entity_t *participants, size_t size)
 | 
			
		||||
dds_return_t dds_lookup_participant (dds_domainid_t domain_id, dds_entity_t *participants, size_t size)
 | 
			
		||||
{
 | 
			
		||||
  if ((participants != NULL && (size <= 0 || size >= INT32_MAX)) || (participants == NULL && size != 0))
 | 
			
		||||
    return DDS_RETCODE_BAD_PARAMETER;
 | 
			
		||||
  dds_return_t ret;
 | 
			
		||||
 | 
			
		||||
  ddsrt_init ();
 | 
			
		||||
  ddsrt_mutex_t * const init_mutex = ddsrt_get_singleton_mutex ();
 | 
			
		||||
  if ((participants != NULL && (size == 0 || size >= INT32_MAX)) || (participants == NULL && size != 0))
 | 
			
		||||
    return DDS_RETCODE_BAD_PARAMETER;
 | 
			
		||||
 | 
			
		||||
  if (participants)
 | 
			
		||||
    participants[0] = 0;
 | 
			
		||||
 | 
			
		||||
  dds_return_t ret = 0;
 | 
			
		||||
  ddsrt_mutex_lock (init_mutex);
 | 
			
		||||
  if (dds_global.m_init_count > 0)
 | 
			
		||||
  if ((ret = dds_init ()) < 0)
 | 
			
		||||
    return ret;
 | 
			
		||||
 | 
			
		||||
  ret = 0;
 | 
			
		||||
  struct dds_domain *dom;
 | 
			
		||||
  ddsrt_mutex_lock (&dds_global.m_mutex);
 | 
			
		||||
  if ((dom = dds_domain_find_locked (domain_id)) != NULL)
 | 
			
		||||
  {
 | 
			
		||||
    struct dds_domain *dom;
 | 
			
		||||
    ddsrt_mutex_lock (&dds_global.m_mutex);
 | 
			
		||||
    if ((dom = dds_domain_find_locked (domain_id)) != NULL)
 | 
			
		||||
    ddsrt_avl_iter_t it;
 | 
			
		||||
    for (dds_entity *e = ddsrt_avl_iter_first (&dds_entity_children_td, &dom->m_entity.m_children, &it); e != NULL; e = ddsrt_avl_iter_next (&it))
 | 
			
		||||
    {
 | 
			
		||||
      ddsrt_avl_iter_t it;
 | 
			
		||||
      for (dds_entity *e = ddsrt_avl_iter_first (&dds_entity_children_td, &dom->m_ppants, &it); e != NULL; e = ddsrt_avl_iter_next (&it))
 | 
			
		||||
      {
 | 
			
		||||
        if ((size_t) ret < size)
 | 
			
		||||
          participants[ret] = e->m_hdllink.hdl;
 | 
			
		||||
        ret++;
 | 
			
		||||
      }
 | 
			
		||||
      if ((size_t) ret < size)
 | 
			
		||||
        participants[ret] = e->m_hdllink.hdl;
 | 
			
		||||
      ret++;
 | 
			
		||||
    }
 | 
			
		||||
    ddsrt_mutex_unlock (&dds_global.m_mutex);
 | 
			
		||||
  }
 | 
			
		||||
  ddsrt_mutex_unlock (init_mutex);
 | 
			
		||||
  ddsrt_fini ();
 | 
			
		||||
  ddsrt_mutex_unlock (&dds_global.m_mutex);
 | 
			
		||||
  dds_delete_impl_pinned (&dds_global.m_entity, DIS_EXPLICIT);
 | 
			
		||||
  return ret;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -38,6 +38,7 @@ static dds_return_t dds_publisher_status_validate (uint32_t mask)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
const struct dds_entity_deriver dds_entity_deriver_publisher = {
 | 
			
		||||
  .interrupt = dds_entity_deriver_dummy_interrupt,
 | 
			
		||||
  .close = dds_entity_deriver_dummy_close,
 | 
			
		||||
  .delete = dds_entity_deriver_dummy_delete,
 | 
			
		||||
  .set_qos = dds_publisher_qos_set,
 | 
			
		||||
| 
						 | 
				
			
			@ -69,6 +70,7 @@ dds_entity_t dds_create_publisher (dds_entity_t participant, const dds_qos_t *qo
 | 
			
		|||
  hdl = dds_entity_init (&pub->m_entity, &par->m_entity, DDS_KIND_PUBLISHER, new_qos, listener, DDS_PUBLISHER_STATUS_MASK);
 | 
			
		||||
  pub->m_entity.m_iid = ddsi_iid_gen ();
 | 
			
		||||
  dds_entity_register_child (&par->m_entity, &pub->m_entity);
 | 
			
		||||
  dds_entity_init_complete (&pub->m_entity);
 | 
			
		||||
  dds_participant_unlock (par);
 | 
			
		||||
  return hdl;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -33,8 +33,9 @@ dds_entity_t dds_create_querycondition (dds_entity_t reader, uint32_t mask, dds_
 | 
			
		|||
    dds_entity_t hdl;
 | 
			
		||||
    dds_readcond *cond = dds_create_readcond (r, DDS_KIND_COND_QUERY, mask, filter);
 | 
			
		||||
    assert (cond);
 | 
			
		||||
    dds_reader_unlock (r);
 | 
			
		||||
    hdl = cond->m_entity.m_hdllink.hdl;
 | 
			
		||||
    dds_entity_init_complete (&cond->m_entity);
 | 
			
		||||
    dds_reader_unlock (r);
 | 
			
		||||
    return hdl;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,7 +14,7 @@
 | 
			
		|||
#include "dds__entity.h"
 | 
			
		||||
#include "dds__reader.h"
 | 
			
		||||
#include "dds/ddsi/ddsi_tkmap.h"
 | 
			
		||||
#include "dds__rhc.h"
 | 
			
		||||
#include "dds/ddsc/dds_rhc.h"
 | 
			
		||||
#include "dds/ddsi/q_thread.h"
 | 
			
		||||
#include "dds/ddsi/q_ephash.h"
 | 
			
		||||
#include "dds/ddsi/q_entity.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -130,7 +130,7 @@ static dds_return_t dds_read_impl (bool take, dds_entity_t reader_or_condition,
 | 
			
		|||
    if (nodata_cleanups & NC_CLEAR_LOAN_OUT)
 | 
			
		||||
      rd->m_loan_out = false;
 | 
			
		||||
    if (nodata_cleanups & NC_FREE_BUF)
 | 
			
		||||
      ddsi_sertopic_free_samples (rd->m_topic->m_stopic, buf[0], maxs, DDS_FREE_ALL);
 | 
			
		||||
      ddsi_sertopic_free_samples (rd->m_topic->m_stopic, buf, maxs, DDS_FREE_ALL);
 | 
			
		||||
    if (nodata_cleanups & NC_RESET_BUF)
 | 
			
		||||
      buf[0] = NULL;
 | 
			
		||||
    ddsrt_mutex_unlock (&rd->m_entity.m_mutex);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,7 +12,7 @@
 | 
			
		|||
#include <assert.h>
 | 
			
		||||
#include "dds__reader.h"
 | 
			
		||||
#include "dds__readcond.h"
 | 
			
		||||
#include "dds__rhc.h"
 | 
			
		||||
#include "dds/ddsc/dds_rhc.h"
 | 
			
		||||
#include "dds__entity.h"
 | 
			
		||||
#include "dds/ddsi/ddsi_iid.h"
 | 
			
		||||
#include "dds/ddsi/q_ephash.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -23,11 +23,14 @@ static dds_return_t dds_readcond_delete (dds_entity *e) ddsrt_nonnull_all;
 | 
			
		|||
 | 
			
		||||
static dds_return_t dds_readcond_delete (dds_entity *e)
 | 
			
		||||
{
 | 
			
		||||
  dds_rhc_remove_readcondition ((dds_readcond *) e);
 | 
			
		||||
  struct dds_reader * const rd = (struct dds_reader *) e->m_parent;
 | 
			
		||||
  assert (dds_entity_kind (&rd->m_entity) == DDS_KIND_READER);
 | 
			
		||||
  dds_rhc_remove_readcondition (rd->m_rhc, (dds_readcond *) e);
 | 
			
		||||
  return DDS_RETCODE_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const struct dds_entity_deriver dds_entity_deriver_readcondition = {
 | 
			
		||||
  .interrupt = dds_entity_deriver_dummy_interrupt,
 | 
			
		||||
  .close = dds_entity_deriver_dummy_close,
 | 
			
		||||
  .delete = dds_readcond_delete,
 | 
			
		||||
  .set_qos = dds_entity_deriver_dummy_set_qos,
 | 
			
		||||
| 
						 | 
				
			
			@ -41,17 +44,15 @@ dds_readcond *dds_create_readcond (dds_reader *rd, dds_entity_kind_t kind, uint3
 | 
			
		|||
  (void) dds_entity_init (&cond->m_entity, &rd->m_entity, kind, NULL, NULL, 0);
 | 
			
		||||
  cond->m_entity.m_iid = ddsi_iid_gen ();
 | 
			
		||||
  dds_entity_register_child (&rd->m_entity, &cond->m_entity);
 | 
			
		||||
  cond->m_rhc = rd->m_rhc;
 | 
			
		||||
  cond->m_sample_states = mask & DDS_ANY_SAMPLE_STATE;
 | 
			
		||||
  cond->m_view_states = mask & DDS_ANY_VIEW_STATE;
 | 
			
		||||
  cond->m_instance_states = mask & DDS_ANY_INSTANCE_STATE;
 | 
			
		||||
  cond->m_rd_guid = rd->m_entity.m_guid;
 | 
			
		||||
  if (kind == DDS_KIND_COND_QUERY)
 | 
			
		||||
  {
 | 
			
		||||
    cond->m_query.m_filter = filter;
 | 
			
		||||
    cond->m_query.m_qcmask = 0;
 | 
			
		||||
  }
 | 
			
		||||
  if (!dds_rhc_add_readcondition (cond))
 | 
			
		||||
  if (!dds_rhc_add_readcondition (rd->m_rhc, cond))
 | 
			
		||||
  {
 | 
			
		||||
    /* FIXME: current entity management code can't deal with an error late in the creation of the
 | 
			
		||||
       entity because it doesn't allow deleting it again ... */
 | 
			
		||||
| 
						 | 
				
			
			@ -72,6 +73,7 @@ dds_entity_t dds_create_readcondition (dds_entity_t reader, uint32_t mask)
 | 
			
		|||
    dds_readcond *cond = dds_create_readcond(rd, DDS_KIND_COND_READ, mask, 0);
 | 
			
		||||
    assert (cond);
 | 
			
		||||
    hdl = cond->m_entity.m_hdllink.hdl;
 | 
			
		||||
    dds_entity_init_complete (&cond->m_entity);
 | 
			
		||||
    dds_reader_unlock (rd);
 | 
			
		||||
    return hdl;
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,7 +18,7 @@
 | 
			
		|||
#include "dds__reader.h"
 | 
			
		||||
#include "dds__listener.h"
 | 
			
		||||
#include "dds__init.h"
 | 
			
		||||
#include "dds__rhc.h"
 | 
			
		||||
#include "dds/ddsc/dds_rhc.h"
 | 
			
		||||
#include "dds__rhc_default.h"
 | 
			
		||||
#include "dds__topic.h"
 | 
			
		||||
#include "dds__get_status.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -40,16 +40,21 @@ DECL_ENTITY_LOCK_UNLOCK (extern inline, dds_reader)
 | 
			
		|||
                         DDS_SAMPLE_LOST_STATUS                  |\
 | 
			
		||||
                         DDS_SUBSCRIPTION_MATCHED_STATUS)
 | 
			
		||||
 | 
			
		||||
static dds_return_t dds_reader_close (dds_entity *e) ddsrt_nonnull_all;
 | 
			
		||||
static void dds_reader_close (dds_entity *e) ddsrt_nonnull_all;
 | 
			
		||||
 | 
			
		||||
static dds_return_t dds_reader_close (dds_entity *e)
 | 
			
		||||
static void dds_reader_close (dds_entity *e)
 | 
			
		||||
{
 | 
			
		||||
  dds_return_t ret = DDS_RETCODE_OK;
 | 
			
		||||
  struct dds_reader * const rd = (struct dds_reader *) e;
 | 
			
		||||
  assert (rd->m_rd != NULL);
 | 
			
		||||
 | 
			
		||||
  thread_state_awake (lookup_thread_state (), &e->m_domain->gv);
 | 
			
		||||
  if (delete_reader (&e->m_domain->gv, &e->m_guid) != 0)
 | 
			
		||||
    ret = DDS_RETCODE_ERROR;
 | 
			
		||||
  (void) delete_reader (&e->m_domain->gv, &e->m_guid);
 | 
			
		||||
  thread_state_asleep (lookup_thread_state ());
 | 
			
		||||
  return ret;
 | 
			
		||||
 | 
			
		||||
  ddsrt_mutex_lock (&e->m_mutex);
 | 
			
		||||
  while (rd->m_rd != NULL)
 | 
			
		||||
    ddsrt_cond_wait (&e->m_cond, &e->m_mutex);
 | 
			
		||||
  ddsrt_mutex_unlock (&e->m_mutex);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static dds_return_t dds_reader_delete (dds_entity *e) ddsrt_nonnull_all;
 | 
			
		||||
| 
						 | 
				
			
			@ -57,17 +62,12 @@ static dds_return_t dds_reader_delete (dds_entity *e) ddsrt_nonnull_all;
 | 
			
		|||
static dds_return_t dds_reader_delete (dds_entity *e)
 | 
			
		||||
{
 | 
			
		||||
  dds_reader * const rd = (dds_reader *) e;
 | 
			
		||||
  dds_return_t ret;
 | 
			
		||||
  if ((ret = dds_delete (rd->m_topic->m_entity.m_hdllink.hdl)) == DDS_RETCODE_OK)
 | 
			
		||||
  {
 | 
			
		||||
    /* Delete an implicitly created parent; for normal ones, this is expected
 | 
			
		||||
       to fail with BAD_PARAMETER - FIXME: there must be a cleaner way */
 | 
			
		||||
    ret = dds_delete_impl (e->m_parent->m_hdllink.hdl, true);
 | 
			
		||||
    if (ret == DDS_RETCODE_BAD_PARAMETER)
 | 
			
		||||
      ret = DDS_RETCODE_OK;
 | 
			
		||||
  }
 | 
			
		||||
  (void) dds_delete (rd->m_topic->m_entity.m_hdllink.hdl);
 | 
			
		||||
  dds_free (rd->m_loan);
 | 
			
		||||
  return ret;
 | 
			
		||||
  thread_state_awake (lookup_thread_state (), &e->m_domain->gv);
 | 
			
		||||
  dds_rhc_free (rd->m_rhc);
 | 
			
		||||
  thread_state_asleep (lookup_thread_state ());
 | 
			
		||||
  return DDS_RETCODE_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static dds_return_t dds_reader_qos_set (dds_entity *e, const dds_qos_t *qos, bool enabled)
 | 
			
		||||
| 
						 | 
				
			
			@ -97,11 +97,14 @@ void dds_reader_data_available_cb (struct dds_reader *rd)
 | 
			
		|||
     overhead really matters.  Otherwise, it is pretty much like
 | 
			
		||||
     dds_reader_status_cb. */
 | 
			
		||||
 | 
			
		||||
  const bool data_av_enabled = (ddsrt_atomic_ld32 (&rd->m_entity.m_status.m_status_and_mask) & (DDS_DATA_AVAILABLE_STATUS << SAM_ENABLED_SHIFT));
 | 
			
		||||
  if (!data_av_enabled)
 | 
			
		||||
  const uint32_t data_av_enabled = (ddsrt_atomic_ld32 (&rd->m_entity.m_status.m_status_and_mask) & (DDS_DATA_AVAILABLE_STATUS << SAM_ENABLED_SHIFT));
 | 
			
		||||
  if (data_av_enabled == 0)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  ddsrt_mutex_lock (&rd->m_entity.m_observers_lock);
 | 
			
		||||
  rd->m_entity.m_cb_pending_count++;
 | 
			
		||||
 | 
			
		||||
  /* FIXME: why wait if no listener is set? */
 | 
			
		||||
  while (rd->m_entity.m_cb_count > 0)
 | 
			
		||||
    ddsrt_cond_wait (&rd->m_entity.m_observers_cond, &rd->m_entity.m_observers_lock);
 | 
			
		||||
  rd->m_entity.m_cb_count++;
 | 
			
		||||
| 
						 | 
				
			
			@ -111,20 +114,25 @@ void dds_reader_data_available_cb (struct dds_reader *rd)
 | 
			
		|||
  if (lst->on_data_on_readers)
 | 
			
		||||
  {
 | 
			
		||||
    ddsrt_mutex_unlock (&rd->m_entity.m_observers_lock);
 | 
			
		||||
 | 
			
		||||
    ddsrt_mutex_lock (&sub->m_observers_lock);
 | 
			
		||||
    while (sub->m_cb_count > 0)
 | 
			
		||||
      ddsrt_cond_wait (&sub->m_observers_cond, &sub->m_observers_lock);
 | 
			
		||||
    sub->m_cb_count++;
 | 
			
		||||
    const uint32_t data_on_rds_enabled = (ddsrt_atomic_ld32 (&sub->m_status.m_status_and_mask) & (DDS_DATA_ON_READERS_STATUS << SAM_ENABLED_SHIFT));
 | 
			
		||||
    if (data_on_rds_enabled)
 | 
			
		||||
    {
 | 
			
		||||
      sub->m_cb_pending_count++;
 | 
			
		||||
      while (sub->m_cb_count > 0)
 | 
			
		||||
        ddsrt_cond_wait (&sub->m_observers_cond, &sub->m_observers_lock);
 | 
			
		||||
      sub->m_cb_count++;
 | 
			
		||||
      ddsrt_mutex_unlock (&sub->m_observers_lock);
 | 
			
		||||
 | 
			
		||||
      lst->on_data_on_readers (sub->m_hdllink.hdl, lst->on_data_on_readers_arg);
 | 
			
		||||
 | 
			
		||||
      ddsrt_mutex_lock (&sub->m_observers_lock);
 | 
			
		||||
      sub->m_cb_count--;
 | 
			
		||||
      sub->m_cb_pending_count--;
 | 
			
		||||
      ddsrt_cond_broadcast (&sub->m_observers_cond);
 | 
			
		||||
    }
 | 
			
		||||
    ddsrt_mutex_unlock (&sub->m_observers_lock);
 | 
			
		||||
 | 
			
		||||
    lst->on_data_on_readers (sub->m_hdllink.hdl, lst->on_data_on_readers_arg);
 | 
			
		||||
 | 
			
		||||
    ddsrt_mutex_lock (&rd->m_entity.m_observers_lock);
 | 
			
		||||
    ddsrt_mutex_lock (&sub->m_observers_lock);
 | 
			
		||||
    sub->m_cb_count--;
 | 
			
		||||
    ddsrt_cond_broadcast (&sub->m_observers_cond);
 | 
			
		||||
    ddsrt_mutex_unlock (&sub->m_observers_lock);
 | 
			
		||||
  }
 | 
			
		||||
  else if (rd->m_entity.m_listener.on_data_available)
 | 
			
		||||
  {
 | 
			
		||||
| 
						 | 
				
			
			@ -141,24 +149,28 @@ void dds_reader_data_available_cb (struct dds_reader *rd)
 | 
			
		|||
  }
 | 
			
		||||
 | 
			
		||||
  rd->m_entity.m_cb_count--;
 | 
			
		||||
  rd->m_entity.m_cb_pending_count--;
 | 
			
		||||
  ddsrt_cond_broadcast (&rd->m_entity.m_observers_cond);
 | 
			
		||||
  ddsrt_mutex_unlock (&rd->m_entity.m_observers_lock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dds_reader_status_cb (void *ventity, const status_cb_data_t *data)
 | 
			
		||||
{
 | 
			
		||||
  struct dds_entity * const entity = ventity;
 | 
			
		||||
  dds_reader * const rd = ventity;
 | 
			
		||||
 | 
			
		||||
  /* When data is NULL, it means that the DDSI reader is deleted. */
 | 
			
		||||
  if (data == NULL)
 | 
			
		||||
  {
 | 
			
		||||
    /* Release the initial claim that was done during the create. This
 | 
			
		||||
     * will indicate that further API deletion is now possible. */
 | 
			
		||||
    dds_handle_unpin (&entity->m_hdllink);
 | 
			
		||||
    ddsrt_mutex_lock (&rd->m_entity.m_mutex);
 | 
			
		||||
    rd->m_rd = NULL;
 | 
			
		||||
    ddsrt_cond_broadcast (&rd->m_entity.m_cond);
 | 
			
		||||
    ddsrt_mutex_unlock (&rd->m_entity.m_mutex);
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  struct dds_listener const * const lst = &entity->m_listener;
 | 
			
		||||
  struct dds_listener const * const lst = &rd->m_entity.m_listener;
 | 
			
		||||
  enum dds_status_id status_id = (enum dds_status_id) data->raw_status_id;
 | 
			
		||||
  bool invoke = false;
 | 
			
		||||
  void *vst = NULL;
 | 
			
		||||
| 
						 | 
				
			
			@ -175,13 +187,12 @@ void dds_reader_status_cb (void *ventity, const status_cb_data_t *data)
 | 
			
		|||
     m_observers_lock for the duration of the listener call itself,
 | 
			
		||||
     and that similarly the listener function and argument pointers
 | 
			
		||||
     are stable */
 | 
			
		||||
  ddsrt_mutex_lock (&entity->m_observers_lock);
 | 
			
		||||
  while (entity->m_cb_count > 0)
 | 
			
		||||
    ddsrt_cond_wait (&entity->m_observers_cond, &entity->m_observers_lock);
 | 
			
		||||
  entity->m_cb_count++;
 | 
			
		||||
  /* FIXME: why do this if no listener is set? */
 | 
			
		||||
  ddsrt_mutex_lock (&rd->m_entity.m_observers_lock);
 | 
			
		||||
  while (rd->m_entity.m_cb_count > 0)
 | 
			
		||||
    ddsrt_cond_wait (&rd->m_entity.m_observers_cond, &rd->m_entity.m_observers_lock);
 | 
			
		||||
 | 
			
		||||
  /* Update status metrics. */
 | 
			
		||||
  dds_reader * const rd = (dds_reader *) entity;
 | 
			
		||||
  switch (status_id) {
 | 
			
		||||
    case DDS_REQUESTED_DEADLINE_MISSED_STATUS_ID: {
 | 
			
		||||
      struct dds_requested_deadline_missed_status * const st = vst = &rd->m_requested_deadline_missed_status;
 | 
			
		||||
| 
						 | 
				
			
			@ -265,36 +276,46 @@ void dds_reader_status_cb (void *ventity, const status_cb_data_t *data)
 | 
			
		|||
      assert (0);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (invoke)
 | 
			
		||||
  const uint32_t enabled = (ddsrt_atomic_ld32 (&rd->m_entity.m_status.m_status_and_mask) & ((1u << status_id) << SAM_ENABLED_SHIFT));
 | 
			
		||||
  if (!enabled)
 | 
			
		||||
  {
 | 
			
		||||
    ddsrt_mutex_unlock (&entity->m_observers_lock);
 | 
			
		||||
    dds_entity_invoke_listener (entity, status_id, vst);
 | 
			
		||||
    ddsrt_mutex_lock (&entity->m_observers_lock);
 | 
			
		||||
    /* Don't invoke listeners or set status flag if masked */
 | 
			
		||||
  }
 | 
			
		||||
  else if (invoke)
 | 
			
		||||
  {
 | 
			
		||||
    rd->m_entity.m_cb_pending_count++;
 | 
			
		||||
    rd->m_entity.m_cb_count++;
 | 
			
		||||
    ddsrt_mutex_unlock (&rd->m_entity.m_observers_lock);
 | 
			
		||||
    dds_entity_invoke_listener (&rd->m_entity, status_id, vst);
 | 
			
		||||
    ddsrt_mutex_lock (&rd->m_entity.m_observers_lock);
 | 
			
		||||
    rd->m_entity.m_cb_count--;
 | 
			
		||||
    rd->m_entity.m_cb_pending_count--;
 | 
			
		||||
    *reset[0] = 0;
 | 
			
		||||
    if (reset[1])
 | 
			
		||||
      *reset[1] = 0;
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
    dds_entity_status_set (entity, (status_mask_t) (1u << status_id));
 | 
			
		||||
    dds_entity_status_set (&rd->m_entity, (status_mask_t) (1u << status_id));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  entity->m_cb_count--;
 | 
			
		||||
  ddsrt_cond_broadcast (&entity->m_observers_cond);
 | 
			
		||||
  ddsrt_mutex_unlock (&entity->m_observers_lock);
 | 
			
		||||
  ddsrt_cond_broadcast (&rd->m_entity.m_observers_cond);
 | 
			
		||||
  ddsrt_mutex_unlock (&rd->m_entity.m_observers_lock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const struct dds_entity_deriver dds_entity_deriver_reader = {
 | 
			
		||||
  .interrupt = dds_entity_deriver_dummy_interrupt,
 | 
			
		||||
  .close = dds_reader_close,
 | 
			
		||||
  .delete = dds_reader_delete,
 | 
			
		||||
  .set_qos = dds_reader_qos_set,
 | 
			
		||||
  .validate_status = dds_reader_status_validate
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
dds_entity_t dds_create_reader (dds_entity_t participant_or_subscriber, dds_entity_t topic, const dds_qos_t *qos, const dds_listener_t *listener)
 | 
			
		||||
static dds_entity_t dds_create_reader_int (dds_entity_t participant_or_subscriber, dds_entity_t topic, const dds_qos_t *qos, const dds_listener_t *listener, struct dds_rhc *rhc)
 | 
			
		||||
{
 | 
			
		||||
  dds_qos_t *rqos;
 | 
			
		||||
  dds_subscriber *sub = NULL;
 | 
			
		||||
  dds_participant *pp;
 | 
			
		||||
  dds_entity_t subscriber;
 | 
			
		||||
  dds_reader *rd;
 | 
			
		||||
  dds_topic *tp;
 | 
			
		||||
| 
						 | 
				
			
			@ -347,8 +368,12 @@ dds_entity_t dds_create_reader (dds_entity_t participant_or_subscriber, dds_enti
 | 
			
		|||
    goto err_tp_lock;
 | 
			
		||||
  }
 | 
			
		||||
  assert (tp->m_stopic);
 | 
			
		||||
  /* FIXME: domain check */
 | 
			
		||||
  assert (sub->m_entity.m_domain == tp->m_entity.m_domain);
 | 
			
		||||
  pp = dds_entity_participant (&sub->m_entity);
 | 
			
		||||
  if (pp != dds_entity_participant (&tp->m_entity))
 | 
			
		||||
  {
 | 
			
		||||
    reader = DDS_RETCODE_BAD_PARAMETER;
 | 
			
		||||
    goto err_pp_mismatch;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /* Merge qos from topic and subscriber, dds_copy_qos only fails when it is passed a null
 | 
			
		||||
     argument, but that isn't the case here */
 | 
			
		||||
| 
						 | 
				
			
			@ -378,28 +403,29 @@ dds_entity_t dds_create_reader (dds_entity_t participant_or_subscriber, dds_enti
 | 
			
		|||
    goto err_bad_qos;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /* Create reader and associated read cache */
 | 
			
		||||
  /* Create reader and associated read cache (if not provided by caller) */
 | 
			
		||||
  rd = dds_alloc (sizeof (*rd));
 | 
			
		||||
  reader = dds_entity_init (&rd->m_entity, &sub->m_entity, DDS_KIND_READER, rqos, listener, DDS_READER_STATUS_MASK);
 | 
			
		||||
  rd->m_sample_rejected_status.last_reason = DDS_NOT_REJECTED;
 | 
			
		||||
  rd->m_topic = tp;
 | 
			
		||||
  rd->m_rhc = dds_rhc_default_new (rd, tp->m_stopic);
 | 
			
		||||
  rd->m_rhc = rhc ? rhc : dds_rhc_default_new (rd, tp->m_stopic);
 | 
			
		||||
  if (dds_rhc_associate (rd->m_rhc, rd, tp->m_stopic, rd->m_entity.m_domain->gv.m_tkmap) < 0)
 | 
			
		||||
  {
 | 
			
		||||
    /* FIXME: see also create_querycond, need to be able to undo entity_init */
 | 
			
		||||
    abort ();
 | 
			
		||||
  }
 | 
			
		||||
  dds_entity_add_ref_locked (&tp->m_entity);
 | 
			
		||||
 | 
			
		||||
  /* Extra claim of this reader to make sure that the delete waits until DDSI
 | 
			
		||||
     has deleted its reader as well. This can be known through the callback. */
 | 
			
		||||
  dds_handle_repin (&rd->m_entity.m_hdllink);
 | 
			
		||||
 | 
			
		||||
  ddsrt_mutex_unlock (&tp->m_entity.m_mutex);
 | 
			
		||||
  ddsrt_mutex_unlock (&sub->m_entity.m_mutex);
 | 
			
		||||
  /* FIXME: listeners can come too soon ... should set mask based on listeners
 | 
			
		||||
     then atomically set the listeners, save the mask to a pending set and clear
 | 
			
		||||
     it; and then invoke those listeners that are in the pending set */
 | 
			
		||||
  dds_entity_init_complete (&rd->m_entity);
 | 
			
		||||
 | 
			
		||||
  thread_state_awake (lookup_thread_state (), &sub->m_entity.m_domain->gv);
 | 
			
		||||
  ret = new_reader (&rd->m_rd, &rd->m_entity.m_domain->gv, &rd->m_entity.m_guid, NULL, &sub->m_entity.m_participant->m_guid, tp->m_stopic, rqos, &rd->m_rhc->common.rhc, dds_reader_status_cb, rd);
 | 
			
		||||
  ddsrt_mutex_lock (&sub->m_entity.m_mutex);
 | 
			
		||||
  ddsrt_mutex_lock (&tp->m_entity.m_mutex);
 | 
			
		||||
  ret = new_reader (&rd->m_rd, &rd->m_entity.m_domain->gv, &rd->m_entity.m_guid, NULL, &pp->m_entity.m_guid, tp->m_stopic, rqos, &rd->m_rhc->common.rhc, dds_reader_status_cb, rd);
 | 
			
		||||
  assert (ret == DDS_RETCODE_OK); /* FIXME: can be out-of-resources at the very least */
 | 
			
		||||
  thread_state_asleep (lookup_thread_state ());
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  rd->m_entity.m_iid = get_entity_instance_id (&rd->m_entity.m_domain->gv, &rd->m_entity.m_guid);
 | 
			
		||||
  dds_entity_register_child (&sub->m_entity, &rd->m_entity);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -414,6 +440,7 @@ dds_entity_t dds_create_reader (dds_entity_t participant_or_subscriber, dds_enti
 | 
			
		|||
  return reader;
 | 
			
		||||
 | 
			
		||||
err_bad_qos:
 | 
			
		||||
err_pp_mismatch:
 | 
			
		||||
  dds_topic_unlock (tp);
 | 
			
		||||
err_tp_lock:
 | 
			
		||||
  dds_subscriber_unlock (sub);
 | 
			
		||||
| 
						 | 
				
			
			@ -438,7 +465,7 @@ void dds_reader_ddsi2direct (dds_entity_t entity, ddsi2direct_directread_cb_t cb
 | 
			
		|||
 | 
			
		||||
  dds_reader *dds_rd = (dds_reader *) dds_entity;
 | 
			
		||||
  struct reader *rd = dds_rd->m_rd;
 | 
			
		||||
  nn_guid_t pwrguid;
 | 
			
		||||
  ddsi_guid_t pwrguid;
 | 
			
		||||
  struct proxy_writer *pwr;
 | 
			
		||||
  struct rd_pwr_match *m;
 | 
			
		||||
  memset (&pwrguid, 0, sizeof (pwrguid));
 | 
			
		||||
| 
						 | 
				
			
			@ -451,7 +478,7 @@ void dds_reader_ddsi2direct (dds_entity_t entity, ddsi2direct_directread_cb_t cb
 | 
			
		|||
    /* have to be careful walking the tree -- pretty is different, but
 | 
			
		||||
       I want to check this before I write a lookup_succ function. */
 | 
			
		||||
    struct rd_pwr_match *m_next;
 | 
			
		||||
    nn_guid_t pwrguid_next;
 | 
			
		||||
    ddsi_guid_t pwrguid_next;
 | 
			
		||||
    pwrguid = m->pwr_guid;
 | 
			
		||||
    if ((m_next = ddsrt_avl_find_succ (&rd_writers_treedef, &rd->writers, m)) != NULL)
 | 
			
		||||
      pwrguid_next = m_next->pwr_guid;
 | 
			
		||||
| 
						 | 
				
			
			@ -475,6 +502,18 @@ void dds_reader_ddsi2direct (dds_entity_t entity, ddsi2direct_directread_cb_t cb
 | 
			
		|||
  dds_entity_unpin (dds_entity);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dds_entity_t dds_create_reader (dds_entity_t participant_or_subscriber, dds_entity_t topic, const dds_qos_t *qos, const dds_listener_t *listener)
 | 
			
		||||
{
 | 
			
		||||
  return dds_create_reader_int (participant_or_subscriber, topic, qos, listener, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dds_entity_t dds_create_reader_rhc (dds_entity_t participant_or_subscriber, dds_entity_t topic, const dds_qos_t *qos, const dds_listener_t *listener, struct dds_rhc *rhc)
 | 
			
		||||
{
 | 
			
		||||
  if (rhc == NULL)
 | 
			
		||||
    return DDS_RETCODE_BAD_PARAMETER;
 | 
			
		||||
  return dds_create_reader_int (participant_or_subscriber, topic, qos, listener, rhc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint32_t dds_reader_lock_samples (dds_entity_t reader)
 | 
			
		||||
{
 | 
			
		||||
  dds_reader *rd;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,17 +11,18 @@
 | 
			
		|||
 */
 | 
			
		||||
 | 
			
		||||
#include "dds/dds.h"
 | 
			
		||||
#include "dds/ddsi/q_rhc.h"
 | 
			
		||||
#include "dds__rhc.h"
 | 
			
		||||
#include "dds/ddsi/ddsi_rhc.h"
 | 
			
		||||
#include "dds/ddsc/dds_rhc.h"
 | 
			
		||||
 | 
			
		||||
extern inline bool dds_rhc_store (struct dds_rhc * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info, struct ddsi_serdata * __restrict sample, struct ddsi_tkmap_instance * __restrict tk);
 | 
			
		||||
extern inline void dds_rhc_unregister_wr (struct dds_rhc * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info);
 | 
			
		||||
extern inline dds_return_t dds_rhc_associate (struct dds_rhc *rhc, struct dds_reader *reader, const struct ddsi_sertopic *topic, struct ddsi_tkmap *tkmap);
 | 
			
		||||
extern inline bool dds_rhc_store (struct dds_rhc * __restrict rhc, const struct ddsi_writer_info * __restrict pwr_info, struct ddsi_serdata * __restrict sample, struct ddsi_tkmap_instance * __restrict tk);
 | 
			
		||||
extern inline void dds_rhc_unregister_wr (struct dds_rhc * __restrict rhc, const struct ddsi_writer_info * __restrict pwr_info);
 | 
			
		||||
extern inline void dds_rhc_relinquish_ownership (struct dds_rhc * __restrict rhc, const uint64_t wr_iid);
 | 
			
		||||
extern inline void dds_rhc_set_qos (struct dds_rhc *rhc, const struct dds_qos *qos);
 | 
			
		||||
extern inline void dds_rhc_free (struct dds_rhc *rhc);
 | 
			
		||||
extern inline int dds_rhc_read (struct dds_rhc *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, dds_readcond *cond);
 | 
			
		||||
extern inline int dds_rhc_take (struct dds_rhc *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, dds_readcond *cond);
 | 
			
		||||
extern inline int dds_rhc_read (struct dds_rhc *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, struct dds_readcond *cond);
 | 
			
		||||
extern inline int dds_rhc_take (struct dds_rhc *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, struct dds_readcond *cond);
 | 
			
		||||
extern inline int dds_rhc_takecdr (struct dds_rhc *rhc, bool lock, struct ddsi_serdata **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t sample_states, uint32_t view_states, uint32_t instance_states, dds_instance_handle_t handle);
 | 
			
		||||
extern inline bool dds_rhc_add_readcondition (struct dds_readcond *cond);
 | 
			
		||||
extern inline void dds_rhc_remove_readcondition (struct dds_readcond *cond);
 | 
			
		||||
extern inline bool dds_rhc_add_readcondition (struct dds_rhc *rhc, struct dds_readcond *cond);
 | 
			
		||||
extern inline void dds_rhc_remove_readcondition (struct dds_rhc *rhc, struct dds_readcond *cond);
 | 
			
		||||
extern inline uint32_t dds_rhc_lock_samples (struct dds_rhc *rhc);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -25,12 +25,12 @@
 | 
			
		|||
 | 
			
		||||
#include "dds__entity.h"
 | 
			
		||||
#include "dds__reader.h"
 | 
			
		||||
#include "dds__rhc.h"
 | 
			
		||||
#include "dds/ddsc/dds_rhc.h"
 | 
			
		||||
#include "dds__rhc_default.h"
 | 
			
		||||
#include "dds/ddsi/ddsi_tkmap.h"
 | 
			
		||||
#include "dds/ddsrt/hopscotch.h"
 | 
			
		||||
#include "dds/ddsrt/avl.h"
 | 
			
		||||
#include "dds/ddsi/q_rhc.h"
 | 
			
		||||
#include "dds/ddsi/ddsi_rhc.h"
 | 
			
		||||
#include "dds/ddsi/q_xqos.h"
 | 
			
		||||
#include "dds/ddsi/q_unused.h"
 | 
			
		||||
#include "dds/ddsi/q_config.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -263,7 +263,7 @@ struct rhc_instance {
 | 
			
		|||
  uint32_t disposed_gen;       /* bloody generation counters - worst invention of mankind */
 | 
			
		||||
  uint32_t no_writers_gen;     /* __/ */
 | 
			
		||||
  int32_t strength;            /* "current" ownership strength */
 | 
			
		||||
  nn_guid_t wr_guid;           /* guid of last writer (if wr_iid != 0 then wr_guid is the corresponding guid, else undef) */
 | 
			
		||||
  ddsi_guid_t wr_guid;           /* guid of last writer (if wr_iid != 0 then wr_guid is the corresponding guid, else undef) */
 | 
			
		||||
  nn_wctime_t tstamp;          /* source time stamp of last update */
 | 
			
		||||
  struct rhc_instance *next;   /* next non-empty instance in arbitrary ordering */
 | 
			
		||||
  struct rhc_instance *prev;
 | 
			
		||||
| 
						 | 
				
			
			@ -346,30 +346,30 @@ struct trigger_info_post {
 | 
			
		|||
};
 | 
			
		||||
 | 
			
		||||
static void dds_rhc_default_free (struct dds_rhc_default *rhc);
 | 
			
		||||
static bool dds_rhc_default_store (struct dds_rhc_default * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info, struct ddsi_serdata * __restrict sample, struct ddsi_tkmap_instance * __restrict tk);
 | 
			
		||||
static void dds_rhc_default_unregister_wr (struct dds_rhc_default * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info);
 | 
			
		||||
static bool dds_rhc_default_store (struct dds_rhc_default * __restrict rhc, const struct ddsi_writer_info * __restrict wrinfo, struct ddsi_serdata * __restrict sample, struct ddsi_tkmap_instance * __restrict tk);
 | 
			
		||||
static void dds_rhc_default_unregister_wr (struct dds_rhc_default * __restrict rhc, const struct ddsi_writer_info * __restrict wrinfo);
 | 
			
		||||
static void dds_rhc_default_relinquish_ownership (struct dds_rhc_default * __restrict rhc, const uint64_t wr_iid);
 | 
			
		||||
static void dds_rhc_default_set_qos (struct dds_rhc_default *rhc, const struct dds_qos *qos);
 | 
			
		||||
static int dds_rhc_default_read (struct dds_rhc_default *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, dds_readcond *cond);
 | 
			
		||||
static int dds_rhc_default_take (struct dds_rhc_default *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, dds_readcond *cond);
 | 
			
		||||
static int dds_rhc_default_takecdr (struct dds_rhc_default *rhc, bool lock, struct ddsi_serdata ** values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t sample_states, uint32_t view_states, uint32_t instance_states, dds_instance_handle_t handle);
 | 
			
		||||
static bool dds_rhc_default_add_readcondition (dds_readcond *cond);
 | 
			
		||||
static void dds_rhc_default_remove_readcondition (dds_readcond *cond);
 | 
			
		||||
static bool dds_rhc_default_add_readcondition (struct dds_rhc_default *rhc, dds_readcond *cond);
 | 
			
		||||
static void dds_rhc_default_remove_readcondition (struct dds_rhc_default *rhc, dds_readcond *cond);
 | 
			
		||||
static uint32_t dds_rhc_default_lock_samples (struct dds_rhc_default *rhc);
 | 
			
		||||
 | 
			
		||||
static void dds_rhc_default_free_wrap (struct rhc *rhc) {
 | 
			
		||||
static void dds_rhc_default_free_wrap (struct ddsi_rhc *rhc) {
 | 
			
		||||
  dds_rhc_default_free ((struct dds_rhc_default *) rhc);
 | 
			
		||||
}
 | 
			
		||||
static bool dds_rhc_default_store_wrap (struct rhc * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info, struct ddsi_serdata * __restrict sample, struct ddsi_tkmap_instance * __restrict tk) {
 | 
			
		||||
  return dds_rhc_default_store ((struct dds_rhc_default *) rhc, pwr_info, sample, tk);
 | 
			
		||||
static bool dds_rhc_default_store_wrap (struct ddsi_rhc * __restrict rhc, const struct ddsi_writer_info * __restrict wrinfo, struct ddsi_serdata * __restrict sample, struct ddsi_tkmap_instance * __restrict tk) {
 | 
			
		||||
  return dds_rhc_default_store ((struct dds_rhc_default *) rhc, wrinfo, sample, tk);
 | 
			
		||||
}
 | 
			
		||||
static void dds_rhc_default_unregister_wr_wrap (struct rhc * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info) {
 | 
			
		||||
  dds_rhc_default_unregister_wr ((struct dds_rhc_default *) rhc, pwr_info);
 | 
			
		||||
static void dds_rhc_default_unregister_wr_wrap (struct ddsi_rhc * __restrict rhc, const struct ddsi_writer_info * __restrict wrinfo) {
 | 
			
		||||
  dds_rhc_default_unregister_wr ((struct dds_rhc_default *) rhc, wrinfo);
 | 
			
		||||
}
 | 
			
		||||
static void dds_rhc_default_relinquish_ownership_wrap (struct rhc * __restrict rhc, const uint64_t wr_iid) {
 | 
			
		||||
static void dds_rhc_default_relinquish_ownership_wrap (struct ddsi_rhc * __restrict rhc, const uint64_t wr_iid) {
 | 
			
		||||
  dds_rhc_default_relinquish_ownership ((struct dds_rhc_default *) rhc, wr_iid);
 | 
			
		||||
}
 | 
			
		||||
static void dds_rhc_default_set_qos_wrap (struct rhc *rhc, const struct dds_qos *qos) {
 | 
			
		||||
static void dds_rhc_default_set_qos_wrap (struct ddsi_rhc *rhc, const struct dds_qos *qos) {
 | 
			
		||||
  dds_rhc_default_set_qos ((struct dds_rhc_default *) rhc, qos);
 | 
			
		||||
}
 | 
			
		||||
static int dds_rhc_default_read_wrap (struct dds_rhc *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, dds_readcond *cond) {
 | 
			
		||||
| 
						 | 
				
			
			@ -381,15 +381,21 @@ static int dds_rhc_default_take_wrap (struct dds_rhc *rhc, bool lock, void **val
 | 
			
		|||
static int dds_rhc_default_takecdr_wrap (struct dds_rhc *rhc, bool lock, struct ddsi_serdata **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t sample_states, uint32_t view_states, uint32_t instance_states, dds_instance_handle_t handle) {
 | 
			
		||||
  return dds_rhc_default_takecdr ((struct dds_rhc_default *) rhc, lock, values, info_seq, max_samples, sample_states, view_states, instance_states, handle);
 | 
			
		||||
}
 | 
			
		||||
static bool dds_rhc_default_add_readcondition_wrap (dds_readcond *cond) {
 | 
			
		||||
  return dds_rhc_default_add_readcondition (cond);
 | 
			
		||||
static bool dds_rhc_default_add_readcondition_wrap (struct dds_rhc *rhc, dds_readcond *cond) {
 | 
			
		||||
  return dds_rhc_default_add_readcondition ((struct dds_rhc_default *) rhc, cond);
 | 
			
		||||
}
 | 
			
		||||
static void dds_rhc_default_remove_readcondition_wrap (dds_readcond *cond) {
 | 
			
		||||
  dds_rhc_default_remove_readcondition (cond);
 | 
			
		||||
static void dds_rhc_default_remove_readcondition_wrap (struct dds_rhc *rhc, dds_readcond *cond) {
 | 
			
		||||
  dds_rhc_default_remove_readcondition ((struct dds_rhc_default *) rhc, cond);
 | 
			
		||||
}
 | 
			
		||||
static uint32_t dds_rhc_default_lock_samples_wrap (struct dds_rhc *rhc) {
 | 
			
		||||
  return dds_rhc_default_lock_samples ((struct dds_rhc_default *) rhc);
 | 
			
		||||
}
 | 
			
		||||
static dds_return_t dds_rhc_default_associate (struct dds_rhc *rhc, dds_reader *reader, const struct ddsi_sertopic *topic, struct ddsi_tkmap *tkmap)
 | 
			
		||||
{
 | 
			
		||||
  /* ignored out of laziness */
 | 
			
		||||
  (void) rhc; (void) reader; (void) topic; (void) tkmap;
 | 
			
		||||
  return DDS_RETCODE_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct dds_rhc_ops dds_rhc_default_ops = {
 | 
			
		||||
  .rhc_ops = {
 | 
			
		||||
| 
						 | 
				
			
			@ -404,7 +410,8 @@ static const struct dds_rhc_ops dds_rhc_default_ops = {
 | 
			
		|||
  .takecdr = dds_rhc_default_takecdr_wrap,
 | 
			
		||||
  .add_readcondition = dds_rhc_default_add_readcondition_wrap,
 | 
			
		||||
  .remove_readcondition = dds_rhc_default_remove_readcondition_wrap,
 | 
			
		||||
  .lock_samples = dds_rhc_default_lock_samples_wrap
 | 
			
		||||
  .lock_samples = dds_rhc_default_lock_samples_wrap,
 | 
			
		||||
  .associate = dds_rhc_default_associate
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static unsigned qmask_of_sample (const struct rhc_sample *s)
 | 
			
		||||
| 
						 | 
				
			
			@ -758,7 +765,7 @@ static bool trigger_info_differs (const struct dds_rhc_default *rhc, const struc
 | 
			
		|||
            trig_qc->dec_sample_read != trig_qc->inc_sample_read);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool add_sample (struct dds_rhc_default *rhc, struct rhc_instance *inst, const struct proxy_writer_info *pwr_info, const struct ddsi_serdata *sample, status_cb_data_t *cb_data, struct trigger_info_qcond *trig_qc)
 | 
			
		||||
static bool add_sample (struct dds_rhc_default *rhc, struct rhc_instance *inst, const struct ddsi_writer_info *wrinfo, const struct ddsi_serdata *sample, status_cb_data_t *cb_data, struct trigger_info_qcond *trig_qc)
 | 
			
		||||
{
 | 
			
		||||
  struct rhc_sample *s;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -832,7 +839,7 @@ static bool add_sample (struct dds_rhc_default *rhc, struct rhc_instance *inst,
 | 
			
		|||
  }
 | 
			
		||||
 | 
			
		||||
  s->sample = ddsi_serdata_ref (sample); /* drops const (tho refcount does change) */
 | 
			
		||||
  s->wr_iid = pwr_info->iid;
 | 
			
		||||
  s->wr_iid = wrinfo->iid;
 | 
			
		||||
  s->isread = false;
 | 
			
		||||
  s->disposed_gen = inst->disposed_gen;
 | 
			
		||||
  s->no_writers_gen = inst->no_writers_gen;
 | 
			
		||||
| 
						 | 
				
			
			@ -867,12 +874,12 @@ static bool content_filter_accepts (const dds_reader *reader, const struct ddsi_
 | 
			
		|||
  return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int inst_accepts_sample_by_writer_guid (const struct rhc_instance *inst, const struct proxy_writer_info *pwr_info)
 | 
			
		||||
static int inst_accepts_sample_by_writer_guid (const struct rhc_instance *inst, const struct ddsi_writer_info *wrinfo)
 | 
			
		||||
{
 | 
			
		||||
  return (inst->wr_iid_islive && inst->wr_iid == pwr_info->iid) || memcmp (&pwr_info->guid, &inst->wr_guid, sizeof (inst->wr_guid)) < 0;
 | 
			
		||||
  return (inst->wr_iid_islive && inst->wr_iid == wrinfo->iid) || memcmp (&wrinfo->guid, &inst->wr_guid, sizeof (inst->wr_guid)) < 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int inst_accepts_sample (const struct dds_rhc_default *rhc, const struct rhc_instance *inst, const struct proxy_writer_info *pwr_info, const struct ddsi_serdata *sample, const bool has_data)
 | 
			
		||||
static int inst_accepts_sample (const struct dds_rhc_default *rhc, const struct rhc_instance *inst, const struct ddsi_writer_info *wrinfo, const struct ddsi_serdata *sample, const bool has_data)
 | 
			
		||||
{
 | 
			
		||||
  if (rhc->by_source_ordering)
 | 
			
		||||
  {
 | 
			
		||||
| 
						 | 
				
			
			@ -884,7 +891,7 @@ static int inst_accepts_sample (const struct dds_rhc_default *rhc, const struct
 | 
			
		|||
    {
 | 
			
		||||
      return 0;
 | 
			
		||||
    }
 | 
			
		||||
    else if (inst_accepts_sample_by_writer_guid (inst, pwr_info))
 | 
			
		||||
    else if (inst_accepts_sample_by_writer_guid (inst, wrinfo))
 | 
			
		||||
    {
 | 
			
		||||
      /* ok */
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -893,14 +900,14 @@ static int inst_accepts_sample (const struct dds_rhc_default *rhc, const struct
 | 
			
		|||
      return 0;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  if (rhc->exclusive_ownership && inst->wr_iid_islive && inst->wr_iid != pwr_info->iid)
 | 
			
		||||
  if (rhc->exclusive_ownership && inst->wr_iid_islive && inst->wr_iid != wrinfo->iid)
 | 
			
		||||
  {
 | 
			
		||||
    int32_t strength = pwr_info->ownership_strength;
 | 
			
		||||
    int32_t strength = wrinfo->ownership_strength;
 | 
			
		||||
    if (strength > inst->strength) {
 | 
			
		||||
      /* ok */
 | 
			
		||||
    } else if (strength < inst->strength) {
 | 
			
		||||
      return 0;
 | 
			
		||||
    } else if (inst_accepts_sample_by_writer_guid (inst, pwr_info)) {
 | 
			
		||||
    } else if (inst_accepts_sample_by_writer_guid (inst, wrinfo)) {
 | 
			
		||||
      /* ok */
 | 
			
		||||
    } else {
 | 
			
		||||
      return 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -913,17 +920,17 @@ static int inst_accepts_sample (const struct dds_rhc_default *rhc, const struct
 | 
			
		|||
  return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void update_inst (struct rhc_instance *inst, const struct proxy_writer_info * __restrict pwr_info, bool wr_iid_valid, nn_wctime_t tstamp)
 | 
			
		||||
static void update_inst (struct rhc_instance *inst, const struct ddsi_writer_info * __restrict wrinfo, bool wr_iid_valid, nn_wctime_t tstamp)
 | 
			
		||||
{
 | 
			
		||||
  inst->tstamp = tstamp;
 | 
			
		||||
  inst->wr_iid_islive = wr_iid_valid;
 | 
			
		||||
  if (wr_iid_valid)
 | 
			
		||||
  {
 | 
			
		||||
    inst->wr_iid = pwr_info->iid;
 | 
			
		||||
    if (inst->wr_iid != pwr_info->iid)
 | 
			
		||||
      inst->wr_guid = pwr_info->guid;
 | 
			
		||||
    inst->wr_iid = wrinfo->iid;
 | 
			
		||||
    if (inst->wr_iid != wrinfo->iid)
 | 
			
		||||
      inst->wr_guid = wrinfo->guid;
 | 
			
		||||
  }
 | 
			
		||||
  inst->strength = pwr_info->ownership_strength;
 | 
			
		||||
  inst->strength = wrinfo->ownership_strength;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void drop_instance_noupdate_no_writers (struct dds_rhc_default *rhc, struct rhc_instance *inst)
 | 
			
		||||
| 
						 | 
				
			
			@ -1109,13 +1116,13 @@ static int rhc_unregister_isreg_w_sideeffects (struct dds_rhc_default *rhc, cons
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int rhc_unregister_updateinst (struct dds_rhc_default *rhc, struct rhc_instance *inst, const struct proxy_writer_info * __restrict pwr_info, nn_wctime_t tstamp, struct trigger_info_qcond *trig_qc, bool *nda)
 | 
			
		||||
static int rhc_unregister_updateinst (struct dds_rhc_default *rhc, struct rhc_instance *inst, const struct ddsi_writer_info * __restrict wrinfo, nn_wctime_t tstamp, struct trigger_info_qcond *trig_qc, bool *nda)
 | 
			
		||||
{
 | 
			
		||||
  assert (inst->wrcount > 0);
 | 
			
		||||
 | 
			
		||||
  if (--inst->wrcount > 0)
 | 
			
		||||
  {
 | 
			
		||||
    if (inst->wr_iid_islive && pwr_info->iid == inst->wr_iid)
 | 
			
		||||
    if (inst->wr_iid_islive && wrinfo->iid == inst->wr_iid)
 | 
			
		||||
    {
 | 
			
		||||
      /* Next register will have to do real work before we have a cached
 | 
			
		||||
       wr_iid again */
 | 
			
		||||
| 
						 | 
				
			
			@ -1142,7 +1149,7 @@ static int rhc_unregister_updateinst (struct dds_rhc_default *rhc, struct rhc_in
 | 
			
		|||
      if (inst->latest == NULL || inst->latest->isread)
 | 
			
		||||
      {
 | 
			
		||||
        inst_set_invsample (rhc, inst, trig_qc, nda);
 | 
			
		||||
        update_inst (inst, pwr_info, false, tstamp);
 | 
			
		||||
        update_inst (inst, wrinfo, false, tstamp);
 | 
			
		||||
      }
 | 
			
		||||
      if (!inst->isdisposed)
 | 
			
		||||
      {
 | 
			
		||||
| 
						 | 
				
			
			@ -1164,7 +1171,7 @@ static int rhc_unregister_updateinst (struct dds_rhc_default *rhc, struct rhc_in
 | 
			
		|||
      TRACE (",#0,empty,nowriters");
 | 
			
		||||
      assert (inst_is_empty (inst));
 | 
			
		||||
      inst_set_invsample (rhc, inst, trig_qc, nda);
 | 
			
		||||
      update_inst (inst, pwr_info, false, tstamp);
 | 
			
		||||
      update_inst (inst, wrinfo, false, tstamp);
 | 
			
		||||
      account_for_empty_to_nonempty_transition (rhc, inst);
 | 
			
		||||
      inst->wr_iid_islive = 0;
 | 
			
		||||
      return 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -1172,18 +1179,18 @@ static int rhc_unregister_updateinst (struct dds_rhc_default *rhc, struct rhc_in
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool dds_rhc_unregister (struct dds_rhc_default *rhc, struct rhc_instance *inst, const struct proxy_writer_info * __restrict pwr_info, nn_wctime_t tstamp, struct trigger_info_post *post, struct trigger_info_qcond *trig_qc)
 | 
			
		||||
static bool dds_rhc_unregister (struct dds_rhc_default *rhc, struct rhc_instance *inst, const struct ddsi_writer_info * __restrict wrinfo, nn_wctime_t tstamp, struct trigger_info_post *post, struct trigger_info_qcond *trig_qc)
 | 
			
		||||
{
 | 
			
		||||
  bool notify_data_available = false;
 | 
			
		||||
 | 
			
		||||
  /* 'post' always gets set; instance may have been freed upon return. */
 | 
			
		||||
  TRACE (" unregister:");
 | 
			
		||||
  if (!rhc_unregister_isreg_w_sideeffects (rhc, inst, pwr_info->iid))
 | 
			
		||||
  if (!rhc_unregister_isreg_w_sideeffects (rhc, inst, wrinfo->iid))
 | 
			
		||||
  {
 | 
			
		||||
    /* other registrations remain */
 | 
			
		||||
    get_trigger_info_cmn (&post->c, inst);
 | 
			
		||||
  }
 | 
			
		||||
  else if (rhc_unregister_updateinst (rhc, inst, pwr_info, tstamp, trig_qc, ¬ify_data_available))
 | 
			
		||||
  else if (rhc_unregister_updateinst (rhc, inst, wrinfo, tstamp, trig_qc, ¬ify_data_available))
 | 
			
		||||
  {
 | 
			
		||||
    /* instance dropped */
 | 
			
		||||
    init_trigger_info_cmn_nonmatch (&post->c);
 | 
			
		||||
| 
						 | 
				
			
			@ -1196,7 +1203,7 @@ static bool dds_rhc_unregister (struct dds_rhc_default *rhc, struct rhc_instance
 | 
			
		|||
  return notify_data_available;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct rhc_instance *alloc_new_instance (const struct dds_rhc_default *rhc, const struct proxy_writer_info *pwr_info, struct ddsi_serdata *serdata, struct ddsi_tkmap_instance *tk)
 | 
			
		||||
static struct rhc_instance *alloc_new_instance (const struct dds_rhc_default *rhc, const struct ddsi_writer_info *wrinfo, struct ddsi_serdata *serdata, struct ddsi_tkmap_instance *tk)
 | 
			
		||||
{
 | 
			
		||||
  struct rhc_instance *inst;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1210,11 +1217,11 @@ static struct rhc_instance *alloc_new_instance (const struct dds_rhc_default *rh
 | 
			
		|||
  inst->isnew = 1;
 | 
			
		||||
  inst->a_sample_free = 1;
 | 
			
		||||
  inst->conds = 0;
 | 
			
		||||
  inst->wr_iid = pwr_info->iid;
 | 
			
		||||
  inst->wr_iid = wrinfo->iid;
 | 
			
		||||
  inst->wr_iid_islive = (inst->wrcount != 0);
 | 
			
		||||
  inst->wr_guid = pwr_info->guid;
 | 
			
		||||
  inst->wr_guid = wrinfo->guid;
 | 
			
		||||
  inst->tstamp = serdata->timestamp;
 | 
			
		||||
  inst->strength = pwr_info->ownership_strength;
 | 
			
		||||
  inst->strength = wrinfo->ownership_strength;
 | 
			
		||||
 | 
			
		||||
  if (rhc->nqconds != 0)
 | 
			
		||||
  {
 | 
			
		||||
| 
						 | 
				
			
			@ -1230,7 +1237,7 @@ static struct rhc_instance *alloc_new_instance (const struct dds_rhc_default *rh
 | 
			
		|||
  return inst;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static rhc_store_result_t rhc_store_new_instance (struct rhc_instance **out_inst, struct dds_rhc_default *rhc, const struct proxy_writer_info *pwr_info, struct ddsi_serdata *sample, struct ddsi_tkmap_instance *tk, const bool has_data, status_cb_data_t *cb_data, struct trigger_info_post *post, struct trigger_info_qcond *trig_qc)
 | 
			
		||||
static rhc_store_result_t rhc_store_new_instance (struct rhc_instance **out_inst, struct dds_rhc_default *rhc, const struct ddsi_writer_info *wrinfo, struct ddsi_serdata *sample, struct ddsi_tkmap_instance *tk, const bool has_data, status_cb_data_t *cb_data, struct trigger_info_post *post, struct trigger_info_qcond *trig_qc)
 | 
			
		||||
{
 | 
			
		||||
  struct rhc_instance *inst;
 | 
			
		||||
  int ret;
 | 
			
		||||
| 
						 | 
				
			
			@ -1265,10 +1272,10 @@ static rhc_store_result_t rhc_store_new_instance (struct rhc_instance **out_inst
 | 
			
		|||
    return RHC_REJECTED;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  inst = alloc_new_instance (rhc, pwr_info, sample, tk);
 | 
			
		||||
  inst = alloc_new_instance (rhc, wrinfo, sample, tk);
 | 
			
		||||
  if (has_data)
 | 
			
		||||
  {
 | 
			
		||||
    if (!add_sample (rhc, inst, pwr_info, sample, cb_data, trig_qc))
 | 
			
		||||
    if (!add_sample (rhc, inst, wrinfo, sample, cb_data, trig_qc))
 | 
			
		||||
    {
 | 
			
		||||
      free_empty_instance (inst, rhc);
 | 
			
		||||
      return RHC_REJECTED;
 | 
			
		||||
| 
						 | 
				
			
			@ -1298,9 +1305,9 @@ static rhc_store_result_t rhc_store_new_instance (struct rhc_instance **out_inst
 | 
			
		|||
  delivered (true unless a reliable sample rejected).
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
static bool dds_rhc_default_store (struct dds_rhc_default * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info, struct ddsi_serdata * __restrict sample, struct ddsi_tkmap_instance * __restrict tk)
 | 
			
		||||
static bool dds_rhc_default_store (struct dds_rhc_default * __restrict rhc, const struct ddsi_writer_info * __restrict wrinfo, struct ddsi_serdata * __restrict sample, struct ddsi_tkmap_instance * __restrict tk)
 | 
			
		||||
{
 | 
			
		||||
  const uint64_t wr_iid = pwr_info->iid;
 | 
			
		||||
  const uint64_t wr_iid = wrinfo->iid;
 | 
			
		||||
  const unsigned statusinfo = sample->statusinfo;
 | 
			
		||||
  const bool has_data = (sample->kind == SDK_DATA);
 | 
			
		||||
  const int is_dispose = (statusinfo & NN_STATUSINFO_DISPOSE) != 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -1347,7 +1354,7 @@ static bool dds_rhc_default_store (struct dds_rhc_default * __restrict rhc, cons
 | 
			
		|||
    else
 | 
			
		||||
    {
 | 
			
		||||
      TRACE (" new instance");
 | 
			
		||||
      stored = rhc_store_new_instance (&inst, rhc, pwr_info, sample, tk, has_data, &cb_data, &post, &trig_qc);
 | 
			
		||||
      stored = rhc_store_new_instance (&inst, rhc, wrinfo, sample, tk, has_data, &cb_data, &post, &trig_qc);
 | 
			
		||||
      if (stored != RHC_STORED)
 | 
			
		||||
      {
 | 
			
		||||
        goto error_or_nochange;
 | 
			
		||||
| 
						 | 
				
			
			@ -1356,7 +1363,7 @@ static bool dds_rhc_default_store (struct dds_rhc_default * __restrict rhc, cons
 | 
			
		|||
      notify_data_available = true;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  else if (!inst_accepts_sample (rhc, inst, pwr_info, sample, has_data))
 | 
			
		||||
  else if (!inst_accepts_sample (rhc, inst, wrinfo, sample, has_data))
 | 
			
		||||
  {
 | 
			
		||||
    /* Rejected samples (and disposes) should still register the writer;
 | 
			
		||||
       unregister *must* be processed, or we have a memory leak. (We
 | 
			
		||||
| 
						 | 
				
			
			@ -1372,7 +1379,7 @@ static bool dds_rhc_default_store (struct dds_rhc_default * __restrict rhc, cons
 | 
			
		|||
    }
 | 
			
		||||
    if (statusinfo & NN_STATUSINFO_UNREGISTER)
 | 
			
		||||
    {
 | 
			
		||||
      if (dds_rhc_unregister (rhc, inst, pwr_info, sample->timestamp, &post, &trig_qc))
 | 
			
		||||
      if (dds_rhc_unregister (rhc, inst, wrinfo, sample->timestamp, &post, &trig_qc))
 | 
			
		||||
        notify_data_available = true;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
| 
						 | 
				
			
			@ -1450,7 +1457,7 @@ static bool dds_rhc_default_store (struct dds_rhc_default * __restrict rhc, cons
 | 
			
		|||
      if (has_data)
 | 
			
		||||
      {
 | 
			
		||||
        TRACE (" add_sample");
 | 
			
		||||
        if (!add_sample (rhc, inst, pwr_info, sample, &cb_data, &trig_qc))
 | 
			
		||||
        if (!add_sample (rhc, inst, wrinfo, sample, &cb_data, &trig_qc))
 | 
			
		||||
        {
 | 
			
		||||
          TRACE ("(reject)");
 | 
			
		||||
          stored = RHC_REJECTED;
 | 
			
		||||
| 
						 | 
				
			
			@ -1469,7 +1476,7 @@ static bool dds_rhc_default_store (struct dds_rhc_default * __restrict rhc, cons
 | 
			
		|||
      if (inst_became_disposed && inst->latest == NULL)
 | 
			
		||||
        inst_set_invsample (rhc, inst, &trig_qc, ¬ify_data_available);
 | 
			
		||||
 | 
			
		||||
      update_inst (inst, pwr_info, true, sample->timestamp);
 | 
			
		||||
      update_inst (inst, wrinfo, true, sample->timestamp);
 | 
			
		||||
 | 
			
		||||
      /* Can only add samples => only need to give special treatment
 | 
			
		||||
         to instances that were empty before.  It is, however, not
 | 
			
		||||
| 
						 | 
				
			
			@ -1513,7 +1520,7 @@ static bool dds_rhc_default_store (struct dds_rhc_default * __restrict rhc, cons
 | 
			
		|||
         mean an application reading "x" after the write and reading it
 | 
			
		||||
         again after the unregister will see a change in the
 | 
			
		||||
         no_writers_generation field? */
 | 
			
		||||
      dds_rhc_unregister (rhc, inst, pwr_info, sample->timestamp, &post, &trig_qc);
 | 
			
		||||
      dds_rhc_unregister (rhc, inst, wrinfo, sample->timestamp, &post, &trig_qc);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -1559,7 +1566,7 @@ error_or_nochange:
 | 
			
		|||
  return delivered;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void dds_rhc_default_unregister_wr (struct dds_rhc_default * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info)
 | 
			
		||||
static void dds_rhc_default_unregister_wr (struct dds_rhc_default * __restrict rhc, const struct ddsi_writer_info * __restrict wrinfo)
 | 
			
		||||
{
 | 
			
		||||
  /* Only to be called when writer with ID WR_IID has died.
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1579,8 +1586,8 @@ static void dds_rhc_default_unregister_wr (struct dds_rhc_default * __restrict r
 | 
			
		|||
  bool notify_data_available = false;
 | 
			
		||||
  struct rhc_instance *inst;
 | 
			
		||||
  struct ddsrt_hh_iter iter;
 | 
			
		||||
  const uint64_t wr_iid = pwr_info->iid;
 | 
			
		||||
  const int auto_dispose = pwr_info->auto_dispose;
 | 
			
		||||
  const uint64_t wr_iid = wrinfo->iid;
 | 
			
		||||
  const int auto_dispose = wrinfo->auto_dispose;
 | 
			
		||||
 | 
			
		||||
  size_t ntriggers = SIZE_MAX;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1620,7 +1627,7 @@ static void dds_rhc_default_unregister_wr (struct dds_rhc_default * __restrict r
 | 
			
		|||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      dds_rhc_unregister (rhc, inst, pwr_info, inst->tstamp, &post, &trig_qc);
 | 
			
		||||
      dds_rhc_unregister (rhc, inst, wrinfo, inst->tstamp, &post, &trig_qc);
 | 
			
		||||
 | 
			
		||||
      TRACE ("\n");
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2292,13 +2299,12 @@ static bool cond_is_sample_state_dependent (const struct dds_readcond *cond)
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool dds_rhc_default_add_readcondition (dds_readcond *cond)
 | 
			
		||||
static bool dds_rhc_default_add_readcondition (struct dds_rhc_default *rhc, dds_readcond *cond)
 | 
			
		||||
{
 | 
			
		||||
  /* On the assumption that a readcondition will be attached to a
 | 
			
		||||
     waitset for nearly all of its life, we keep track of all
 | 
			
		||||
     readconditions on a reader in one set, without distinguishing
 | 
			
		||||
     between those attached to a waitset or not. */
 | 
			
		||||
  struct dds_rhc_default *rhc = (struct dds_rhc_default *) cond->m_rhc;
 | 
			
		||||
  struct ddsrt_hh_iter it;
 | 
			
		||||
 | 
			
		||||
  assert ((dds_entity_kind (&cond->m_entity) == DDS_KIND_COND_READ && cond->m_query.m_filter == 0) ||
 | 
			
		||||
| 
						 | 
				
			
			@ -2397,9 +2403,8 @@ static bool dds_rhc_default_add_readcondition (dds_readcond *cond)
 | 
			
		|||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void dds_rhc_default_remove_readcondition (dds_readcond *cond)
 | 
			
		||||
static void dds_rhc_default_remove_readcondition (struct dds_rhc_default *rhc, dds_readcond *cond)
 | 
			
		||||
{
 | 
			
		||||
  struct dds_rhc_default *rhc = (struct dds_rhc_default *) cond->m_rhc;
 | 
			
		||||
  dds_readcond **ptr;
 | 
			
		||||
  ddsrt_mutex_lock (&rhc->lock);
 | 
			
		||||
  ptr = &rhc->conds;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -32,7 +32,7 @@ static const uint64_t unihashconsts[] = {
 | 
			
		|||
  UINT64_C (16728792139623414127)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static uint32_t hash_guid (const nn_guid_t *g)
 | 
			
		||||
static uint32_t hash_guid (const ddsi_guid_t *g)
 | 
			
		||||
{
 | 
			
		||||
  return
 | 
			
		||||
  (uint32_t) (((((uint32_t) g->prefix.u[0] + unihashconsts[0]) *
 | 
			
		||||
| 
						 | 
				
			
			@ -131,7 +131,7 @@ static struct ddsi_serdata *ddsi_serdata_builtin_from_keyhash (const struct ddsi
 | 
			
		|||
  /* FIXME: not quite elegant to manage the creation of a serdata for a built-in topic via this function, but I also find it quite unelegant to let from_sample read straight from the underlying internal entity, and to_sample convert to the external format ... I could claim the internal entity is the "serialised form", but that forces wrapping it in a fragchain in one way or another, which, though possible, is also a bit lacking in elegance. */
 | 
			
		||||
  const struct ddsi_sertopic_builtintopic *tp = (const struct ddsi_sertopic_builtintopic *)tpcmn;
 | 
			
		||||
  /* keyhash must in host format (which the GUIDs always are internally) */
 | 
			
		||||
  struct entity_common *entity = ephash_lookup_guid_untyped (tp->gv->guid_hash, (const nn_guid_t *) keyhash->value);
 | 
			
		||||
  struct entity_common *entity = ephash_lookup_guid_untyped (tp->gv->guid_hash, (const ddsi_guid_t *) keyhash->value);
 | 
			
		||||
  struct ddsi_serdata_builtintopic *d = serdata_builtin_new(tp, entity ? SDK_DATA : SDK_KEY);
 | 
			
		||||
  memcpy (&d->key, keyhash->value, sizeof (d->key));
 | 
			
		||||
  if (entity)
 | 
			
		||||
| 
						 | 
				
			
			@ -175,9 +175,9 @@ static struct ddsi_serdata *serdata_builtin_to_topicless (const struct ddsi_serd
 | 
			
		|||
  return ddsi_serdata_ref (serdata_common);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void convkey (dds_builtintopic_guid_t *key, const nn_guid_t *guid)
 | 
			
		||||
static void convkey (dds_builtintopic_guid_t *key, const ddsi_guid_t *guid)
 | 
			
		||||
{
 | 
			
		||||
  nn_guid_t tmp;
 | 
			
		||||
  ddsi_guid_t tmp;
 | 
			
		||||
  tmp = nn_hton_guid (*guid);
 | 
			
		||||
  memcpy (key, &tmp, sizeof (*key));
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -214,7 +214,7 @@ static bool to_sample_pp (const struct ddsi_serdata_builtintopic *d, struct dds_
 | 
			
		|||
 | 
			
		||||
static bool to_sample_endpoint (const struct ddsi_serdata_builtintopic *d, struct dds_builtintopic_endpoint *sample)
 | 
			
		||||
{
 | 
			
		||||
  nn_guid_t ppguid;
 | 
			
		||||
  ddsi_guid_t ppguid;
 | 
			
		||||
  convkey (&sample->key, &d->key);
 | 
			
		||||
  ppguid = d->key;
 | 
			
		||||
  ppguid.entityid.u = NN_ENTITYID_PARTICIPANT;
 | 
			
		||||
| 
						 | 
				
			
			@ -276,6 +276,12 @@ static void serdata_builtin_to_ser_unref (struct ddsi_serdata *serdata_common, c
 | 
			
		|||
  (void)serdata_common; (void)ref;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static size_t serdata_builtin_topic_print (const struct ddsi_sertopic *topic, const struct ddsi_serdata *serdata_common, char *buf, size_t size)
 | 
			
		||||
{
 | 
			
		||||
  (void)topic; (void)serdata_common;
 | 
			
		||||
  return (size_t) snprintf (buf, size, "(blob)");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const struct ddsi_serdata_ops ddsi_serdata_ops_builtintopic = {
 | 
			
		||||
  .get_size = serdata_builtin_get_size,
 | 
			
		||||
  .eqkey = serdata_builtin_eqkey,
 | 
			
		||||
| 
						 | 
				
			
			@ -288,5 +294,6 @@ const struct ddsi_serdata_ops ddsi_serdata_ops_builtintopic = {
 | 
			
		|||
  .to_ser_ref = serdata_builtin_to_ser_ref,
 | 
			
		||||
  .to_ser_unref = serdata_builtin_to_ser_unref,
 | 
			
		||||
  .to_topicless = serdata_builtin_to_topicless,
 | 
			
		||||
  .topicless_to_sample = serdata_builtin_topicless_to_sample
 | 
			
		||||
  .topicless_to_sample = serdata_builtin_topicless_to_sample,
 | 
			
		||||
  .print = serdata_builtin_topic_print
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,6 +11,7 @@
 | 
			
		|||
 */
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <ctype.h>
 | 
			
		||||
 | 
			
		||||
#include "dds/ddsrt/endian.h"
 | 
			
		||||
#include "dds/ddsrt/md5.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -1608,6 +1609,292 @@ void dds_stream_extract_keyhash (dds_istream_t * __restrict is, dds_keyhash_t *
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*******************************************************************************************
 | 
			
		||||
 **
 | 
			
		||||
 **  Pretty-printing
 | 
			
		||||
 **
 | 
			
		||||
 *******************************************************************************************/
 | 
			
		||||
 | 
			
		||||
/* Returns true if buffer not yet exhausted, false otherwise */
 | 
			
		||||
static bool prtf (char * __restrict *buf, size_t * __restrict bufsize, const char *fmt, ...)
 | 
			
		||||
{
 | 
			
		||||
  va_list ap;
 | 
			
		||||
  if (*bufsize == 0)
 | 
			
		||||
    return false;
 | 
			
		||||
  va_start (ap, fmt);
 | 
			
		||||
  int n = vsnprintf (*buf, *bufsize, fmt, ap);
 | 
			
		||||
  va_end (ap);
 | 
			
		||||
  if (n < 0)
 | 
			
		||||
  {
 | 
			
		||||
    **buf = 0;
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
  else if ((size_t) n <= *bufsize)
 | 
			
		||||
  {
 | 
			
		||||
    *buf += (size_t) n;
 | 
			
		||||
    *bufsize -= (size_t) n;
 | 
			
		||||
    return (*bufsize > 0);
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
    *buf += *bufsize;
 | 
			
		||||
    *bufsize = 0;
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool prtf_str (char * __restrict *buf, size_t * __restrict bufsize, dds_istream_t * __restrict is)
 | 
			
		||||
{
 | 
			
		||||
  size_t sz = dds_is_get4 (is);
 | 
			
		||||
  bool ret = prtf (buf, bufsize, "\"%s\"", is->m_buffer + is->m_index);
 | 
			
		||||
  is->m_index += (uint32_t) sz;
 | 
			
		||||
  return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static size_t isprint_runlen (const unsigned char *s, size_t n)
 | 
			
		||||
{
 | 
			
		||||
  size_t m;
 | 
			
		||||
  for (m = 0; m < n && s[m] != '"' && isprint (s[m]); m++)
 | 
			
		||||
    ;
 | 
			
		||||
  return m;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool prtf_simple (char * __restrict *buf, size_t * __restrict bufsize, dds_istream_t * __restrict is, enum dds_stream_typecode type)
 | 
			
		||||
{
 | 
			
		||||
  switch (type)
 | 
			
		||||
  {
 | 
			
		||||
    case DDS_OP_VAL_1BY: return prtf (buf, bufsize, "%"PRIu8, dds_is_get1 (is));
 | 
			
		||||
    case DDS_OP_VAL_2BY: return prtf (buf, bufsize, "%"PRIu16, dds_is_get2 (is));
 | 
			
		||||
    case DDS_OP_VAL_4BY: return prtf (buf, bufsize, "%"PRIu32, dds_is_get4 (is));
 | 
			
		||||
    case DDS_OP_VAL_8BY: return prtf (buf, bufsize, "%"PRIu64, dds_is_get8 (is));
 | 
			
		||||
    case DDS_OP_VAL_STR: case DDS_OP_VAL_BST: return prtf_str (buf, bufsize, is);
 | 
			
		||||
    case DDS_OP_VAL_ARR: case DDS_OP_VAL_SEQ: case DDS_OP_VAL_UNI: case DDS_OP_VAL_STU:
 | 
			
		||||
      abort ();
 | 
			
		||||
  }
 | 
			
		||||
  return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool prtf_simple_array (char * __restrict *buf, size_t * __restrict bufsize, dds_istream_t * __restrict is, uint32_t num, enum dds_stream_typecode type)
 | 
			
		||||
{
 | 
			
		||||
  bool cont = prtf (buf, bufsize, "{");
 | 
			
		||||
  switch (type)
 | 
			
		||||
  {
 | 
			
		||||
    case DDS_OP_VAL_1BY: {
 | 
			
		||||
      size_t i = 0, j;
 | 
			
		||||
      while (cont && i < num)
 | 
			
		||||
      {
 | 
			
		||||
        size_t m = isprint_runlen ((unsigned char *) (is->m_buffer + is->m_index), num - i);
 | 
			
		||||
        if (m >= 4)
 | 
			
		||||
        {
 | 
			
		||||
          cont = prtf (buf, bufsize, "%s\"", i != 0 ? "," : "");
 | 
			
		||||
          for (j = 0; cont && j < m; j++)
 | 
			
		||||
            cont = prtf (buf, bufsize, "%c", is->m_buffer[is->m_index + j]);
 | 
			
		||||
          cont = prtf (buf, bufsize, "\"");
 | 
			
		||||
          is->m_index += (uint32_t) m;
 | 
			
		||||
          i += m;
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
          if (i != 0)
 | 
			
		||||
            (void) prtf (buf, bufsize, ",");
 | 
			
		||||
          cont = prtf_simple (buf, bufsize, is, type);
 | 
			
		||||
          i++;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case DDS_OP_VAL_2BY: case DDS_OP_VAL_4BY: case DDS_OP_VAL_8BY:
 | 
			
		||||
    case DDS_OP_VAL_STR: case DDS_OP_VAL_BST:
 | 
			
		||||
      for (size_t i = 0; cont && i < num; i++)
 | 
			
		||||
      {
 | 
			
		||||
        if (i != 0)
 | 
			
		||||
          (void) prtf (buf, bufsize, ",");
 | 
			
		||||
        cont = prtf_simple (buf, bufsize, is, type);
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
    default:
 | 
			
		||||
      abort ();
 | 
			
		||||
      break;
 | 
			
		||||
  }
 | 
			
		||||
  return cont;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool dds_stream_print_sample1 (char * __restrict *buf, size_t * __restrict bufsize, dds_istream_t * __restrict is, const uint32_t * __restrict ops, bool add_braces);
 | 
			
		||||
 | 
			
		||||
static const uint32_t *prtf_seq (char * __restrict *buf, size_t *bufsize, dds_istream_t * __restrict is, const uint32_t * __restrict ops, uint32_t insn)
 | 
			
		||||
{
 | 
			
		||||
  const enum dds_stream_typecode subtype = DDS_OP_SUBTYPE (insn);
 | 
			
		||||
  uint32_t num;
 | 
			
		||||
  num = dds_is_get4 (is);
 | 
			
		||||
  if (num == 0)
 | 
			
		||||
  {
 | 
			
		||||
    prtf (buf, bufsize, "{}");
 | 
			
		||||
    return skip_sequence_insns (ops, insn);
 | 
			
		||||
  }
 | 
			
		||||
  switch (subtype)
 | 
			
		||||
  {
 | 
			
		||||
    case DDS_OP_VAL_1BY: case DDS_OP_VAL_2BY: case DDS_OP_VAL_4BY: case DDS_OP_VAL_8BY:
 | 
			
		||||
      prtf_simple_array (buf, bufsize, is, num, subtype);
 | 
			
		||||
      return ops + 2;
 | 
			
		||||
    case DDS_OP_VAL_STR: case DDS_OP_VAL_BST:
 | 
			
		||||
      prtf_simple_array (buf, bufsize, is, num, subtype);
 | 
			
		||||
      return ops + (subtype == DDS_OP_VAL_STR ? 2 : 3);
 | 
			
		||||
    case DDS_OP_VAL_SEQ: case DDS_OP_VAL_ARR: case DDS_OP_VAL_UNI: case DDS_OP_VAL_STU: {
 | 
			
		||||
      const uint32_t jmp = DDS_OP_ADR_JMP (ops[3]);
 | 
			
		||||
      uint32_t const * const jsr_ops = ops + DDS_OP_ADR_JSR (ops[3]);
 | 
			
		||||
      bool cont = prtf (buf, bufsize, "{");
 | 
			
		||||
      for (uint32_t i = 0; cont && i < num; i++)
 | 
			
		||||
      {
 | 
			
		||||
        if (i > 0) prtf (buf, bufsize, ",");
 | 
			
		||||
        cont = dds_stream_print_sample1 (buf, bufsize, is, jsr_ops, subtype == DDS_OP_VAL_STU);
 | 
			
		||||
      }
 | 
			
		||||
      prtf (buf, bufsize, "}");
 | 
			
		||||
      return ops + (jmp ? jmp : 4); /* FIXME: why would jmp be 0? */
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const uint32_t *prtf_arr (char * __restrict *buf, size_t *bufsize, dds_istream_t * __restrict is, const uint32_t * __restrict ops, uint32_t insn)
 | 
			
		||||
{
 | 
			
		||||
  const enum dds_stream_typecode subtype = DDS_OP_SUBTYPE (insn);
 | 
			
		||||
  const uint32_t num = ops[2];
 | 
			
		||||
  switch (subtype)
 | 
			
		||||
  {
 | 
			
		||||
    case DDS_OP_VAL_1BY: case DDS_OP_VAL_2BY: case DDS_OP_VAL_4BY: case DDS_OP_VAL_8BY:
 | 
			
		||||
      prtf_simple_array (buf, bufsize, is, num, subtype);
 | 
			
		||||
      return ops + 3;
 | 
			
		||||
    case DDS_OP_VAL_STR: case DDS_OP_VAL_BST:
 | 
			
		||||
      prtf_simple_array (buf, bufsize, is, num, subtype);
 | 
			
		||||
      return ops + (subtype == DDS_OP_VAL_STR ? 3 : 5);
 | 
			
		||||
    case DDS_OP_VAL_SEQ: case DDS_OP_VAL_ARR: case DDS_OP_VAL_UNI: case DDS_OP_VAL_STU: {
 | 
			
		||||
      const uint32_t *jsr_ops = ops + DDS_OP_ADR_JSR (ops[3]);
 | 
			
		||||
      const uint32_t jmp = DDS_OP_ADR_JMP (ops[3]);
 | 
			
		||||
      bool cont = prtf (buf, bufsize, "{");
 | 
			
		||||
      for (uint32_t i = 0; cont && i < num; i++)
 | 
			
		||||
      {
 | 
			
		||||
        if (i > 0) prtf (buf, bufsize, ",");
 | 
			
		||||
        cont = dds_stream_print_sample1 (buf, bufsize, is, jsr_ops, subtype == DDS_OP_VAL_STU);
 | 
			
		||||
      }
 | 
			
		||||
      prtf (buf, bufsize, "}");
 | 
			
		||||
      return ops + (jmp ? jmp : 5);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const uint32_t *prtf_uni (char * __restrict *buf, size_t *bufsize, dds_istream_t * __restrict is, const uint32_t * __restrict ops, uint32_t insn)
 | 
			
		||||
{
 | 
			
		||||
  const uint32_t disc = read_union_discriminant (is, DDS_OP_SUBTYPE (insn));
 | 
			
		||||
  uint32_t const * const jeq_op = find_union_case (ops, disc);
 | 
			
		||||
  prtf (buf, bufsize, "%"PRIu32":", disc);
 | 
			
		||||
  ops += DDS_OP_ADR_JMP (ops[3]);
 | 
			
		||||
  if (jeq_op)
 | 
			
		||||
  {
 | 
			
		||||
    const enum dds_stream_typecode valtype = DDS_JEQ_TYPE (jeq_op[0]);
 | 
			
		||||
    switch (valtype)
 | 
			
		||||
    {
 | 
			
		||||
      case DDS_OP_VAL_1BY: case DDS_OP_VAL_2BY: case DDS_OP_VAL_4BY: case DDS_OP_VAL_8BY:
 | 
			
		||||
      case DDS_OP_VAL_STR: case DDS_OP_VAL_BST:
 | 
			
		||||
        prtf_simple (buf, bufsize, is, valtype);
 | 
			
		||||
        break;
 | 
			
		||||
      case DDS_OP_VAL_SEQ: case DDS_OP_VAL_ARR: case DDS_OP_VAL_UNI: case DDS_OP_VAL_STU:
 | 
			
		||||
        dds_stream_print_sample1 (buf, bufsize, is, jeq_op + DDS_OP_ADR_JSR (jeq_op[0]), valtype == DDS_OP_VAL_STU);
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return ops;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool dds_stream_print_sample1 (char * __restrict *buf, size_t * __restrict bufsize, dds_istream_t * __restrict is, const uint32_t * __restrict ops, bool add_braces)
 | 
			
		||||
{
 | 
			
		||||
  uint32_t insn;
 | 
			
		||||
  bool cont = true;
 | 
			
		||||
  bool needs_comma = false;
 | 
			
		||||
  if (add_braces)
 | 
			
		||||
    prtf (buf, bufsize, "{");
 | 
			
		||||
  while (cont && (insn = *ops) != DDS_OP_RTS)
 | 
			
		||||
  {
 | 
			
		||||
    if (needs_comma)
 | 
			
		||||
      prtf (buf, bufsize, ",");
 | 
			
		||||
    needs_comma = true;
 | 
			
		||||
    switch (DDS_OP (insn))
 | 
			
		||||
    {
 | 
			
		||||
      case DDS_OP_ADR: {
 | 
			
		||||
        switch (DDS_OP_TYPE (insn))
 | 
			
		||||
        {
 | 
			
		||||
          case DDS_OP_VAL_1BY: case DDS_OP_VAL_2BY: case DDS_OP_VAL_4BY: case DDS_OP_VAL_8BY:
 | 
			
		||||
          case DDS_OP_VAL_STR:
 | 
			
		||||
            cont = prtf_simple (buf, bufsize, is, DDS_OP_TYPE (insn));
 | 
			
		||||
            ops += 2;
 | 
			
		||||
            break;
 | 
			
		||||
          case DDS_OP_VAL_BST:
 | 
			
		||||
            cont = prtf_simple (buf, bufsize, is, DDS_OP_TYPE (insn));
 | 
			
		||||
            ops += 3;
 | 
			
		||||
            break;
 | 
			
		||||
          case DDS_OP_VAL_SEQ:
 | 
			
		||||
            ops = prtf_seq (buf, bufsize, is, ops, insn);
 | 
			
		||||
            break;
 | 
			
		||||
          case DDS_OP_VAL_ARR:
 | 
			
		||||
            ops = prtf_arr (buf, bufsize, is, ops, insn);
 | 
			
		||||
            break;
 | 
			
		||||
          case DDS_OP_VAL_UNI:
 | 
			
		||||
            ops = prtf_uni (buf, bufsize, is, ops, insn);
 | 
			
		||||
            break;
 | 
			
		||||
          case DDS_OP_VAL_STU:
 | 
			
		||||
            abort ();
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case DDS_OP_JSR: {
 | 
			
		||||
        cont = dds_stream_print_sample1 (buf, bufsize, is, ops + DDS_OP_JUMP (insn), true);
 | 
			
		||||
        ops++;
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case DDS_OP_RTS: case DDS_OP_JEQ: {
 | 
			
		||||
        abort ();
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  if (add_braces)
 | 
			
		||||
    prtf (buf, bufsize, "}");
 | 
			
		||||
  return cont;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t dds_stream_print_sample (dds_istream_t * __restrict is, const struct ddsi_sertopic_default * __restrict topic, char * __restrict buf, size_t bufsize)
 | 
			
		||||
{
 | 
			
		||||
  dds_stream_print_sample1 (&buf, &bufsize, is, topic->type->m_ops, true);
 | 
			
		||||
  return bufsize;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t dds_stream_print_key (dds_istream_t * __restrict is, const struct ddsi_sertopic_default * __restrict topic, char * __restrict buf, size_t bufsize)
 | 
			
		||||
{
 | 
			
		||||
  const dds_topic_descriptor_t *desc = topic->type;
 | 
			
		||||
  bool cont = prtf (&buf, &bufsize, ":k:{");
 | 
			
		||||
  for (uint32_t i = 0; cont && i < desc->m_nkeys; i++)
 | 
			
		||||
  {
 | 
			
		||||
    const uint32_t *op = desc->m_ops + desc->m_keys[i].m_index;
 | 
			
		||||
    assert (insn_key_ok_p (*op));
 | 
			
		||||
    switch (DDS_OP_TYPE (*op))
 | 
			
		||||
    {
 | 
			
		||||
      case DDS_OP_VAL_1BY: case DDS_OP_VAL_2BY: case DDS_OP_VAL_4BY: case DDS_OP_VAL_8BY:
 | 
			
		||||
      case DDS_OP_VAL_STR: case DDS_OP_VAL_BST:
 | 
			
		||||
        cont = prtf_simple (&buf, &bufsize, is, DDS_OP_TYPE (*op));
 | 
			
		||||
        break;
 | 
			
		||||
      case DDS_OP_VAL_ARR:
 | 
			
		||||
        cont = prtf_simple_array (&buf, &bufsize, is, op[2], DDS_OP_SUBTYPE (*op));
 | 
			
		||||
        break;
 | 
			
		||||
      case DDS_OP_VAL_SEQ: case DDS_OP_VAL_UNI: case DDS_OP_VAL_STU:
 | 
			
		||||
        abort ();
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  prtf (&buf, &bufsize, "}");
 | 
			
		||||
  return bufsize;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*******************************************************************************************
 | 
			
		||||
 **
 | 
			
		||||
 **  Stuff to make it possible to treat a ddsi_serdata_default as a stream
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -38,6 +38,7 @@ static dds_return_t dds_subscriber_status_validate (uint32_t mask)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
const struct dds_entity_deriver dds_entity_deriver_subscriber = {
 | 
			
		||||
  .interrupt = dds_entity_deriver_dummy_interrupt,
 | 
			
		||||
  .close = dds_entity_deriver_dummy_close,
 | 
			
		||||
  .delete = dds_entity_deriver_dummy_delete,
 | 
			
		||||
  .set_qos = dds_subscriber_qos_set,
 | 
			
		||||
| 
						 | 
				
			
			@ -66,6 +67,7 @@ dds_entity_t dds__create_subscriber_l (dds_participant *participant, const dds_q
 | 
			
		|||
  subscriber = dds_entity_init (&sub->m_entity, &participant->m_entity, DDS_KIND_SUBSCRIBER, new_qos, listener, DDS_SUBSCRIBER_STATUS_MASK);
 | 
			
		||||
  sub->m_entity.m_iid = ddsi_iid_gen ();
 | 
			
		||||
  dds_entity_register_child (&participant->m_entity, &sub->m_entity);
 | 
			
		||||
  dds_entity_init_complete (&sub->m_entity);
 | 
			
		||||
  return subscriber;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -131,7 +131,7 @@ static bool dds_find_topic_check_and_add_ref (dds_entity_t participant, dds_enti
 | 
			
		|||
    return false;
 | 
			
		||||
 | 
			
		||||
  bool ret;
 | 
			
		||||
  if (tp->m_entity.m_participant->m_hdllink.hdl != participant || strcmp (tp->m_stopic->name, name) != 0)
 | 
			
		||||
  if (dds_entity_participant (&tp->m_entity)->m_entity.m_hdllink.hdl != participant || strcmp (tp->m_stopic->name, name) != 0)
 | 
			
		||||
    ret = false;
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
| 
						 | 
				
			
			@ -243,7 +243,7 @@ static bool sertopic_equivalent (const struct ddsi_sertopic *a, const struct dds
 | 
			
		|||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static dds_return_t create_topic_topic_arbirary_check_sertopic (dds_entity_t participant, dds_entity_t topic, struct ddsi_sertopic *sertopic, const dds_qos_t *qos)
 | 
			
		||||
static dds_return_t create_topic_topic_arbitrary_check_sertopic (dds_entity_t participant, dds_entity_t topic, struct ddsi_sertopic *sertopic, const dds_qos_t *qos)
 | 
			
		||||
{
 | 
			
		||||
  dds_topic *tp;
 | 
			
		||||
  dds_return_t ret;
 | 
			
		||||
| 
						 | 
				
			
			@ -251,7 +251,7 @@ static dds_return_t create_topic_topic_arbirary_check_sertopic (dds_entity_t par
 | 
			
		|||
  if (dds_topic_lock (topic, &tp) < 0)
 | 
			
		||||
    return DDS_RETCODE_NOT_FOUND;
 | 
			
		||||
 | 
			
		||||
  if (tp->m_entity.m_participant->m_hdllink.hdl != participant)
 | 
			
		||||
  if (dds_entity_participant (&tp->m_entity)->m_entity.m_hdllink.hdl != participant)
 | 
			
		||||
    ret = DDS_RETCODE_NOT_FOUND;
 | 
			
		||||
  else if (!sertopic_equivalent (tp->m_stopic, sertopic))
 | 
			
		||||
    ret = DDS_RETCODE_PRECONDITION_NOT_MET;
 | 
			
		||||
| 
						 | 
				
			
			@ -272,6 +272,7 @@ static dds_return_t create_topic_topic_arbirary_check_sertopic (dds_entity_t par
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
const struct dds_entity_deriver dds_entity_deriver_topic = {
 | 
			
		||||
  .interrupt = dds_entity_deriver_dummy_interrupt,
 | 
			
		||||
  .close = dds_entity_deriver_dummy_close,
 | 
			
		||||
  .delete = dds_topic_delete,
 | 
			
		||||
  .set_qos = dds_topic_qos_set,
 | 
			
		||||
| 
						 | 
				
			
			@ -296,6 +297,14 @@ dds_entity_t dds_create_topic_arbitrary (dds_entity_t participant, struct ddsi_s
 | 
			
		|||
     existing topic's compatibility */
 | 
			
		||||
  if ((rc = dds_entity_pin (participant, &par_ent)) < 0)
 | 
			
		||||
    return rc;
 | 
			
		||||
  /* Verify that we've been given a participant, not strictly necessary
 | 
			
		||||
     because dds_participant_lock below checks it, but this is more
 | 
			
		||||
     obvious */
 | 
			
		||||
  if (dds_entity_kind (par_ent) != DDS_KIND_PARTICIPANT)
 | 
			
		||||
  {
 | 
			
		||||
    dds_entity_unpin (par_ent);
 | 
			
		||||
    return DDS_RETCODE_ILLEGAL_OPERATION;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  new_qos = dds_create_qos ();
 | 
			
		||||
  if (qos)
 | 
			
		||||
| 
						 | 
				
			
			@ -351,7 +360,7 @@ dds_entity_t dds_create_topic_arbitrary (dds_entity_t participant, struct ddsi_s
 | 
			
		|||
         for the various scary cases. */
 | 
			
		||||
      dds_participant_unlock (par);
 | 
			
		||||
 | 
			
		||||
      rc = create_topic_topic_arbirary_check_sertopic (participant, topic, sertopic, new_qos);
 | 
			
		||||
      rc = create_topic_topic_arbitrary_check_sertopic (participant, topic, sertopic, new_qos);
 | 
			
		||||
      switch (rc)
 | 
			
		||||
      {
 | 
			
		||||
        case DDS_RETCODE_OK: /* duplicate definition */
 | 
			
		||||
| 
						 | 
				
			
			@ -439,6 +448,8 @@ dds_entity_t dds_create_topic_arbitrary (dds_entity_t participant, struct ddsi_s
 | 
			
		|||
    nn_plist_fini (&plist);
 | 
			
		||||
  }
 | 
			
		||||
  thread_state_asleep (lookup_thread_state ());
 | 
			
		||||
 | 
			
		||||
  dds_entity_init_complete (&top->m_entity);
 | 
			
		||||
  dds_participant_unlock (par);
 | 
			
		||||
  dds_entity_unpin (par_ent);
 | 
			
		||||
  return hdl;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
 | 
			
		||||
 * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others
 | 
			
		||||
 *
 | 
			
		||||
 * This program and the accompanying materials are made available under the
 | 
			
		||||
 * terms of the Eclipse Public License v. 2.0 which is available at
 | 
			
		||||
| 
						 | 
				
			
			@ -17,11 +17,10 @@
 | 
			
		|||
#include "dds__participant.h"
 | 
			
		||||
#include "dds__querycond.h"
 | 
			
		||||
#include "dds__readcond.h"
 | 
			
		||||
#include "dds__rhc.h"
 | 
			
		||||
#include "dds__init.h"
 | 
			
		||||
#include "dds/ddsc/dds_rhc.h"
 | 
			
		||||
#include "dds/ddsi/ddsi_iid.h"
 | 
			
		||||
 | 
			
		||||
DEFINE_ENTITY_LOCK_UNLOCK (static, dds_waitset, DDS_KIND_WAITSET)
 | 
			
		||||
 | 
			
		||||
static bool is_triggered (struct dds_entity *e)
 | 
			
		||||
{
 | 
			
		||||
  bool t;
 | 
			
		||||
| 
						 | 
				
			
			@ -63,7 +62,7 @@ static dds_return_t dds_waitset_wait_impl (dds_entity_t waitset, dds_attach_t *x
 | 
			
		|||
  }
 | 
			
		||||
 | 
			
		||||
  /* Move any previously but no longer triggering entities back to the observed list */
 | 
			
		||||
  ddsrt_mutex_lock (&ws->m_entity.m_mutex);
 | 
			
		||||
  ddsrt_mutex_lock (&ws->wait_lock);
 | 
			
		||||
  ws->ntriggered = 0;
 | 
			
		||||
  for (size_t i = 0; i < ws->nentities; i++)
 | 
			
		||||
  {
 | 
			
		||||
| 
						 | 
				
			
			@ -76,83 +75,195 @@ static dds_return_t dds_waitset_wait_impl (dds_entity_t waitset, dds_attach_t *x
 | 
			
		|||
  }
 | 
			
		||||
 | 
			
		||||
  /* Only wait/keep waiting when we have something to observe and there aren't any triggers yet. */
 | 
			
		||||
  while (ws->nentities > 0 && ws->ntriggered == 0)
 | 
			
		||||
    if (!ddsrt_cond_waituntil (&ws->m_entity.m_cond, &ws->m_entity.m_mutex, abstimeout))
 | 
			
		||||
  while (ws->nentities > 0 && ws->ntriggered == 0 && !dds_handle_is_closed (&ws->m_entity.m_hdllink))
 | 
			
		||||
    if (!ddsrt_cond_waituntil (&ws->wait_cond, &ws->wait_lock, abstimeout))
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
  ret = (int32_t) ws->ntriggered;
 | 
			
		||||
  for (size_t i = 0; i < ws->ntriggered && i < nxs; i++)
 | 
			
		||||
    xs[i] = ws->entities[i].arg;
 | 
			
		||||
  ddsrt_mutex_unlock (&ws->m_entity.m_mutex);
 | 
			
		||||
  ddsrt_mutex_unlock (&ws->wait_lock);
 | 
			
		||||
  dds_entity_unpin (&ws->m_entity);
 | 
			
		||||
  return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static dds_return_t dds_waitset_close (struct dds_entity *e)
 | 
			
		||||
static void dds_waitset_interrupt (struct dds_entity *e)
 | 
			
		||||
{
 | 
			
		||||
  /* deep in the process of deleting the entity, so this is the only thread */
 | 
			
		||||
  dds_waitset *ws = (dds_waitset *) e;
 | 
			
		||||
  for (size_t i = 0; i < ws->nentities; i++)
 | 
			
		||||
    (void) dds_entity_observer_unregister (ws->entities[i].entity, &ws->m_entity);
 | 
			
		||||
  return DDS_RETCODE_OK;
 | 
			
		||||
  ddsrt_mutex_lock (&ws->wait_lock);
 | 
			
		||||
  assert (dds_handle_is_closed (&ws->m_entity.m_hdllink));
 | 
			
		||||
  ddsrt_cond_broadcast (&ws->wait_cond);
 | 
			
		||||
  ddsrt_mutex_unlock (&ws->wait_lock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void dds_waitset_close (struct dds_entity *e)
 | 
			
		||||
{
 | 
			
		||||
  dds_waitset *ws = (dds_waitset *) e;
 | 
			
		||||
  ddsrt_mutex_lock (&ws->wait_lock);
 | 
			
		||||
  while (ws->nentities > 0)
 | 
			
		||||
  {
 | 
			
		||||
    dds_entity *observed;
 | 
			
		||||
    if (dds_entity_pin (ws->entities[0].handle, &observed) < 0)
 | 
			
		||||
    {
 | 
			
		||||
      /* can't be pinned => being deleted => will be removed from wait set soon enough
 | 
			
		||||
       and go through delete_observer (which will trigger the condition variable) */
 | 
			
		||||
      ddsrt_cond_wait (&ws->wait_cond, &ws->wait_lock);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
      /* entity will remain in existence */
 | 
			
		||||
      ddsrt_mutex_unlock (&ws->wait_lock);
 | 
			
		||||
      (void) dds_entity_observer_unregister (observed, ws, true);
 | 
			
		||||
      ddsrt_mutex_lock (&ws->wait_lock);
 | 
			
		||||
      assert (ws->nentities == 0 || ws->entities[0].entity != observed);
 | 
			
		||||
      dds_entity_unpin (observed);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  ddsrt_mutex_unlock (&ws->wait_lock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static dds_return_t dds_waitset_delete (struct dds_entity *e)
 | 
			
		||||
{
 | 
			
		||||
  /* deep in the process of deleting the entity, so this is the only thread */
 | 
			
		||||
  dds_waitset *ws = (dds_waitset *) e;
 | 
			
		||||
  ddsrt_mutex_destroy (&ws->wait_lock);
 | 
			
		||||
  ddsrt_cond_destroy (&ws->wait_cond);
 | 
			
		||||
  ddsrt_free (ws->entities);
 | 
			
		||||
  return DDS_RETCODE_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const struct dds_entity_deriver dds_entity_deriver_waitset = {
 | 
			
		||||
  .interrupt = dds_waitset_interrupt,
 | 
			
		||||
  .close = dds_waitset_close,
 | 
			
		||||
  .delete = dds_waitset_delete,
 | 
			
		||||
  .set_qos = dds_entity_deriver_dummy_set_qos,
 | 
			
		||||
  .validate_status = dds_entity_deriver_dummy_validate_status
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
dds_entity_t dds_create_waitset (dds_entity_t participant)
 | 
			
		||||
dds_entity_t dds_create_waitset (dds_entity_t owner)
 | 
			
		||||
{
 | 
			
		||||
  dds_entity_t hdl;
 | 
			
		||||
  dds_participant *par;
 | 
			
		||||
  dds_entity *e;
 | 
			
		||||
  dds_return_t rc;
 | 
			
		||||
 | 
			
		||||
  if ((rc = dds_participant_lock (participant, &par)) != DDS_RETCODE_OK)
 | 
			
		||||
  /* If the owner is any ordinary (allowed) entity, the library is already initialised and calling
 | 
			
		||||
     init here is cheap.  If it is DDS_CYCLONEDDS_HANDLE, we may have to initialise the library, so
 | 
			
		||||
     have to call it.  If it is some bogus value and the library is not initialised yet ... so be
 | 
			
		||||
     it.  Naturally, this requires us to call delete on DDS_CYCLONEDDS_HANDLE afterward. */
 | 
			
		||||
  if ((rc = dds_init ()) < 0)
 | 
			
		||||
    return rc;
 | 
			
		||||
 | 
			
		||||
  if ((rc = dds_entity_lock (owner, DDS_KIND_DONTCARE, &e)) != DDS_RETCODE_OK)
 | 
			
		||||
    goto err_entity_lock;
 | 
			
		||||
 | 
			
		||||
  switch (dds_entity_kind (e))
 | 
			
		||||
  {
 | 
			
		||||
    case DDS_KIND_CYCLONEDDS:
 | 
			
		||||
    case DDS_KIND_DOMAIN:
 | 
			
		||||
    case DDS_KIND_PARTICIPANT:
 | 
			
		||||
      break;
 | 
			
		||||
    default:
 | 
			
		||||
      rc = DDS_RETCODE_ILLEGAL_OPERATION;
 | 
			
		||||
      goto err_entity_kind;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  dds_waitset *waitset = dds_alloc (sizeof (*waitset));
 | 
			
		||||
  hdl = dds_entity_init (&waitset->m_entity, &par->m_entity, DDS_KIND_WAITSET, NULL, NULL, 0);
 | 
			
		||||
  dds_entity_t hdl = dds_entity_init (&waitset->m_entity, e, DDS_KIND_WAITSET, NULL, NULL, 0);
 | 
			
		||||
  ddsrt_mutex_init (&waitset->wait_lock);
 | 
			
		||||
  ddsrt_cond_init (&waitset->wait_cond);
 | 
			
		||||
  waitset->m_entity.m_iid = ddsi_iid_gen ();
 | 
			
		||||
  dds_entity_register_child (&par->m_entity, &waitset->m_entity);
 | 
			
		||||
  dds_entity_register_child (e, &waitset->m_entity);
 | 
			
		||||
  waitset->nentities = 0;
 | 
			
		||||
  waitset->ntriggered = 0;
 | 
			
		||||
  waitset->entities = NULL;
 | 
			
		||||
  dds_participant_unlock (par);
 | 
			
		||||
  dds_entity_init_complete (&waitset->m_entity);
 | 
			
		||||
  dds_entity_unlock (e);
 | 
			
		||||
  dds_delete_impl_pinned (&dds_global.m_entity, DIS_EXPLICIT);
 | 
			
		||||
  return hdl;
 | 
			
		||||
 | 
			
		||||
 err_entity_kind:
 | 
			
		||||
  dds_entity_unlock (e);
 | 
			
		||||
 err_entity_lock:
 | 
			
		||||
  dds_delete_impl_pinned (&dds_global.m_entity, DIS_EXPLICIT);
 | 
			
		||||
  return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dds_return_t dds_waitset_get_entities (dds_entity_t waitset, dds_entity_t *entities, size_t size)
 | 
			
		||||
{
 | 
			
		||||
  dds_return_t ret;
 | 
			
		||||
  dds_waitset *ws;
 | 
			
		||||
 | 
			
		||||
  if ((ret = dds_waitset_lock (waitset, &ws)) != DDS_RETCODE_OK)
 | 
			
		||||
  dds_entity *wsent;
 | 
			
		||||
  if ((ret = dds_entity_pin (waitset, &wsent)) < 0)
 | 
			
		||||
    return ret;
 | 
			
		||||
 | 
			
		||||
  if (entities != NULL)
 | 
			
		||||
  else if (dds_entity_kind (wsent) != DDS_KIND_WAITSET)
 | 
			
		||||
  {
 | 
			
		||||
    for (size_t i = 0; i < ws->nentities && i < size; i++)
 | 
			
		||||
      entities[i] = ws->entities[i].handle;
 | 
			
		||||
    dds_entity_unpin (wsent);
 | 
			
		||||
    return DDS_RETCODE_ILLEGAL_OPERATION;
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
    dds_waitset *ws = (dds_waitset *) wsent;
 | 
			
		||||
    ddsrt_mutex_lock (&ws->wait_lock);
 | 
			
		||||
    if (entities != NULL)
 | 
			
		||||
    {
 | 
			
		||||
      for (size_t i = 0; i < ws->nentities && i < size; i++)
 | 
			
		||||
        entities[i] = ws->entities[i].handle;
 | 
			
		||||
    }
 | 
			
		||||
    ret = (int32_t) ws->nentities;
 | 
			
		||||
    ddsrt_mutex_unlock (&ws->wait_lock);
 | 
			
		||||
    dds_entity_unpin (&ws->m_entity);
 | 
			
		||||
    return ret;
 | 
			
		||||
  }
 | 
			
		||||
  ret = (int32_t) ws->nentities;
 | 
			
		||||
  dds_waitset_unlock (ws);
 | 
			
		||||
  return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void dds_waitset_remove (dds_waitset *ws, dds_entity_t observed)
 | 
			
		||||
/* This is called when the observed entity signals a status change. */
 | 
			
		||||
static void dds_waitset_observer (struct dds_waitset *ws, dds_entity_t observed, uint32_t status)
 | 
			
		||||
{
 | 
			
		||||
  (void) status;
 | 
			
		||||
 | 
			
		||||
  ddsrt_mutex_lock (&ws->wait_lock);
 | 
			
		||||
  /* Move observed entity to triggered list. */
 | 
			
		||||
  size_t i;
 | 
			
		||||
  for (i = 0; i < ws->nentities; i++)
 | 
			
		||||
    if (ws->entities[i].handle == observed)
 | 
			
		||||
      break;
 | 
			
		||||
  if (i < ws->nentities && i >= ws->ntriggered)
 | 
			
		||||
  {
 | 
			
		||||
    dds_attachment tmp = ws->entities[i];
 | 
			
		||||
    ws->entities[i] = ws->entities[ws->ntriggered];
 | 
			
		||||
    ws->entities[ws->ntriggered++] = tmp;
 | 
			
		||||
  }
 | 
			
		||||
  /* Trigger waitset to wake up. */
 | 
			
		||||
  ddsrt_cond_broadcast (&ws->wait_cond);
 | 
			
		||||
  ddsrt_mutex_unlock (&ws->wait_lock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct dds_waitset_attach_observer_arg {
 | 
			
		||||
  dds_attach_t x;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static bool dds_waitset_attach_observer (struct dds_waitset *ws, struct dds_entity *observed, void *varg)
 | 
			
		||||
{
 | 
			
		||||
  struct dds_waitset_attach_observer_arg *arg = varg;
 | 
			
		||||
  ddsrt_mutex_lock (&ws->wait_lock);
 | 
			
		||||
  ws->entities = ddsrt_realloc (ws->entities, (ws->nentities + 1) * sizeof (*ws->entities));
 | 
			
		||||
  ws->entities[ws->nentities].arg = arg->x;
 | 
			
		||||
  ws->entities[ws->nentities].entity = observed;
 | 
			
		||||
  ws->entities[ws->nentities].handle = observed->m_hdllink.hdl;
 | 
			
		||||
  ws->nentities++;
 | 
			
		||||
  if (is_triggered (observed))
 | 
			
		||||
  {
 | 
			
		||||
    const size_t i = ws->nentities - 1;
 | 
			
		||||
    dds_attachment tmp = ws->entities[i];
 | 
			
		||||
    ws->entities[i] = ws->entities[ws->ntriggered];
 | 
			
		||||
    ws->entities[ws->ntriggered++] = tmp;
 | 
			
		||||
  }
 | 
			
		||||
  ddsrt_cond_broadcast (&ws->wait_cond);
 | 
			
		||||
  ddsrt_mutex_unlock (&ws->wait_lock);
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void dds_waitset_delete_observer (struct dds_waitset *ws, dds_entity_t observed)
 | 
			
		||||
{
 | 
			
		||||
  size_t i;
 | 
			
		||||
  ddsrt_mutex_lock (&ws->wait_lock);
 | 
			
		||||
  for (i = 0; i < ws->nentities; i++)
 | 
			
		||||
    if (ws->entities[i].handle == observed)
 | 
			
		||||
      break;
 | 
			
		||||
| 
						 | 
				
			
			@ -167,118 +278,85 @@ static void dds_waitset_remove (dds_waitset *ws, dds_entity_t observed)
 | 
			
		|||
    {
 | 
			
		||||
      ws->entities[i] = ws->entities[--ws->nentities];
 | 
			
		||||
    }
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* This is called when the observed entity signals a status change. */
 | 
			
		||||
static void dds_waitset_observer (dds_entity *ent, dds_entity_t observed, uint32_t status)
 | 
			
		||||
{
 | 
			
		||||
  assert (dds_entity_kind (ent) == DDS_KIND_WAITSET);
 | 
			
		||||
  dds_waitset *ws = (dds_waitset *) ent;
 | 
			
		||||
  (void) status;
 | 
			
		||||
 | 
			
		||||
  ddsrt_mutex_lock (&ws->m_entity.m_mutex);
 | 
			
		||||
  /* Move observed entity to triggered list. */
 | 
			
		||||
  size_t i;
 | 
			
		||||
  for (i = 0; i < ws->nentities; i++)
 | 
			
		||||
    if (ws->entities[i].handle == observed)
 | 
			
		||||
      break;
 | 
			
		||||
  if (i < ws->nentities && i >= ws->ntriggered)
 | 
			
		||||
  {
 | 
			
		||||
    dds_attachment tmp = ws->entities[i];
 | 
			
		||||
    ws->entities[i] = ws->entities[ws->ntriggered];
 | 
			
		||||
    ws->entities[ws->ntriggered++] = tmp;
 | 
			
		||||
  }
 | 
			
		||||
  /* Trigger waitset to wake up. */
 | 
			
		||||
  ddsrt_cond_broadcast (&ws->m_entity.m_cond);
 | 
			
		||||
  ddsrt_mutex_unlock (&ws->m_entity.m_mutex);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void dds_waitset_delete_observer (dds_entity *ent, dds_entity_t observed)
 | 
			
		||||
{
 | 
			
		||||
  assert (dds_entity_kind (ent) == DDS_KIND_WAITSET);
 | 
			
		||||
  dds_waitset *ws = (dds_waitset *) ent;
 | 
			
		||||
  ddsrt_mutex_lock (&ws->m_entity.m_mutex);
 | 
			
		||||
  /* Remove this observed entity, which is being deleted, from the waitset. */
 | 
			
		||||
  dds_waitset_remove (ws, observed);
 | 
			
		||||
  /* Our registration to this observed entity will be removed automatically. */
 | 
			
		||||
  /* Trigger waitset to wake up. */
 | 
			
		||||
  ddsrt_cond_broadcast (&ws->m_entity.m_cond);
 | 
			
		||||
  ddsrt_mutex_unlock (&ws->m_entity.m_mutex);
 | 
			
		||||
  ddsrt_cond_broadcast (&ws->wait_cond);
 | 
			
		||||
  ddsrt_mutex_unlock (&ws->wait_lock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dds_return_t dds_waitset_attach (dds_entity_t waitset, dds_entity_t entity, dds_attach_t x)
 | 
			
		||||
{
 | 
			
		||||
  dds_entity *wsent;
 | 
			
		||||
  dds_entity *e;
 | 
			
		||||
  dds_waitset *ws;
 | 
			
		||||
  dds_return_t ret;
 | 
			
		||||
 | 
			
		||||
  if ((ret = dds_waitset_lock (waitset, &ws)) < 0)
 | 
			
		||||
  if ((ret = dds_entity_pin (waitset, &wsent)) < 0)
 | 
			
		||||
    return ret;
 | 
			
		||||
 | 
			
		||||
  if (waitset == entity)
 | 
			
		||||
    e = &ws->m_entity;
 | 
			
		||||
  else if ((ret = dds_entity_pin (entity, &e)) < 0)
 | 
			
		||||
    goto err_waitset;
 | 
			
		||||
 | 
			
		||||
  /* This will fail if given entity is already attached (or deleted). */
 | 
			
		||||
  if ((ret = dds_entity_observer_register (e, &ws->m_entity, dds_waitset_observer, dds_waitset_delete_observer)) != DDS_RETCODE_OK)
 | 
			
		||||
    goto err_entity;
 | 
			
		||||
 | 
			
		||||
  ws->entities = ddsrt_realloc (ws->entities, (ws->nentities + 1) * sizeof (*ws->entities));
 | 
			
		||||
  ws->entities[ws->nentities].arg = x;
 | 
			
		||||
  ws->entities[ws->nentities].entity = e;
 | 
			
		||||
  ws->entities[ws->nentities].handle = e->m_hdllink.hdl;
 | 
			
		||||
  ws->nentities++;
 | 
			
		||||
  if (is_triggered (e))
 | 
			
		||||
  else if (dds_entity_kind (wsent) != DDS_KIND_WAITSET)
 | 
			
		||||
  {
 | 
			
		||||
    const size_t i = ws->nentities - 1;
 | 
			
		||||
    dds_attachment tmp = ws->entities[i];
 | 
			
		||||
    ws->entities[i] = ws->entities[ws->ntriggered];
 | 
			
		||||
    ws->entities[ws->ntriggered++] = tmp;
 | 
			
		||||
    dds_entity_unpin (wsent);
 | 
			
		||||
    return DDS_RETCODE_ILLEGAL_OPERATION;
 | 
			
		||||
  }
 | 
			
		||||
  ddsrt_cond_broadcast (&ws->m_entity.m_cond);
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
    dds_waitset *ws = (dds_waitset *) wsent;
 | 
			
		||||
 | 
			
		||||
err_entity:
 | 
			
		||||
  if (e != &ws->m_entity)
 | 
			
		||||
    if ((ret = dds_entity_pin (entity, &e)) < 0)
 | 
			
		||||
      goto err_entity;
 | 
			
		||||
 | 
			
		||||
    /* Entity must be "in scope": within the participant, domain or (self-evidently true) Cyclone DDS,
 | 
			
		||||
       depending on the parent of the waitset, so that one can't use a waitset created in participant
 | 
			
		||||
       A to wait for entities in participant B, &c.  While there is no technical obstacle (though
 | 
			
		||||
       there might be one for cross-domain use one day), it seems rather unhygienic practice. */
 | 
			
		||||
    if (!dds_entity_in_scope (e, ws->m_entity.m_parent))
 | 
			
		||||
    {
 | 
			
		||||
      ret = DDS_RETCODE_BAD_PARAMETER;
 | 
			
		||||
      goto err_scope;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* This will fail if given entity is already attached (or deleted). */
 | 
			
		||||
    struct dds_waitset_attach_observer_arg attach_arg = { .x = x };
 | 
			
		||||
    ret = dds_entity_observer_register (e, ws, dds_waitset_observer, dds_waitset_attach_observer, &attach_arg, dds_waitset_delete_observer);
 | 
			
		||||
 | 
			
		||||
  err_scope:
 | 
			
		||||
    dds_entity_unpin (e);
 | 
			
		||||
err_waitset:
 | 
			
		||||
  dds_waitset_unlock (ws);
 | 
			
		||||
  return ret;
 | 
			
		||||
  err_entity:
 | 
			
		||||
    dds_entity_unpin (&ws->m_entity);
 | 
			
		||||
    return ret;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dds_return_t dds_waitset_detach (dds_entity_t waitset, dds_entity_t entity)
 | 
			
		||||
{
 | 
			
		||||
  dds_waitset *ws;
 | 
			
		||||
  dds_entity *e;
 | 
			
		||||
  dds_entity *wsent;
 | 
			
		||||
  dds_return_t ret;
 | 
			
		||||
 | 
			
		||||
  if ((ret = dds_waitset_lock (waitset, &ws)) != DDS_RETCODE_OK)
 | 
			
		||||
  if ((ret = dds_entity_pin (waitset, &wsent)) != DDS_RETCODE_OK)
 | 
			
		||||
    return ret;
 | 
			
		||||
 | 
			
		||||
  /* Possibly fails when entity was not attached. */
 | 
			
		||||
  if (waitset == entity)
 | 
			
		||||
    ret = dds_entity_observer_unregister (&ws->m_entity, &ws->m_entity);
 | 
			
		||||
  else if ((ret = dds_entity_pin (entity, &e)) < 0)
 | 
			
		||||
    ; /* entity invalid */
 | 
			
		||||
  else
 | 
			
		||||
  else if (dds_entity_kind (wsent) != DDS_KIND_WAITSET)
 | 
			
		||||
  {
 | 
			
		||||
    ret = dds_entity_observer_unregister (e, &ws->m_entity);
 | 
			
		||||
    dds_entity_unpin (e);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (ret == DDS_RETCODE_OK)
 | 
			
		||||
  {
 | 
			
		||||
    dds_waitset_remove (ws, entity);
 | 
			
		||||
    dds_entity_unpin (wsent);
 | 
			
		||||
    return DDS_RETCODE_ILLEGAL_OPERATION;
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
    if (ret != DDS_RETCODE_PRECONDITION_NOT_MET)
 | 
			
		||||
    dds_waitset *ws = (dds_waitset *) wsent;
 | 
			
		||||
    dds_entity *e;
 | 
			
		||||
    /* Possibly fails when entity was not attached. */
 | 
			
		||||
    if (waitset == entity)
 | 
			
		||||
      ret = dds_entity_observer_unregister (&ws->m_entity, ws, true);
 | 
			
		||||
    else if ((ret = dds_entity_pin (entity, &e)) < 0)
 | 
			
		||||
      ; /* entity invalid */
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
      ret = dds_entity_observer_unregister (e, ws, true);
 | 
			
		||||
      dds_entity_unpin (e);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    dds_entity_unpin (&ws->m_entity);
 | 
			
		||||
    if (ret != DDS_RETCODE_OK && ret != DDS_RETCODE_PRECONDITION_NOT_MET)
 | 
			
		||||
      ret = DDS_RETCODE_BAD_PARAMETER;
 | 
			
		||||
    return ret;
 | 
			
		||||
  }
 | 
			
		||||
  dds_waitset_unlock (ws);
 | 
			
		||||
  return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dds_return_t dds_waitset_wait_until (dds_entity_t waitset, dds_attach_t *xs, size_t nxs, dds_time_t abstimeout)
 | 
			
		||||
| 
						 | 
				
			
			@ -299,7 +377,6 @@ dds_return_t dds_waitset_set_trigger (dds_entity_t waitset, bool trigger)
 | 
			
		|||
{
 | 
			
		||||
  dds_entity *ent;
 | 
			
		||||
  dds_return_t rc;
 | 
			
		||||
 | 
			
		||||
  if ((rc = dds_entity_pin (waitset, &ent)) != DDS_RETCODE_OK)
 | 
			
		||||
    return rc;
 | 
			
		||||
  else if (dds_entity_kind (ent) != DDS_KIND_WAITSET)
 | 
			
		||||
| 
						 | 
				
			
			@ -307,11 +384,10 @@ dds_return_t dds_waitset_set_trigger (dds_entity_t waitset, bool trigger)
 | 
			
		|||
    dds_entity_unpin (ent);
 | 
			
		||||
    return DDS_RETCODE_ILLEGAL_OPERATION;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ddsrt_mutex_lock (&ent->m_observers_lock);
 | 
			
		||||
  dds_entity_trigger_set (ent, trigger);
 | 
			
		||||
  ddsrt_mutex_unlock (&ent->m_observers_lock);
 | 
			
		||||
 | 
			
		||||
  dds_entity_unpin (ent);
 | 
			
		||||
  return DDS_RETCODE_OK;
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
    dds_entity_trigger_set (ent, trigger);
 | 
			
		||||
    dds_entity_unpin (ent);
 | 
			
		||||
    return DDS_RETCODE_OK;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -981,21 +981,14 @@ static uint32_t whc_default_remove_acked_messages_full (struct whc_impl *whc, se
 | 
			
		|||
          /* Delete it - but this may not result in deleting the index node as
 | 
			
		||||
           there must still be a more recent one available */
 | 
			
		||||
#ifndef NDEBUG
 | 
			
		||||
          struct whc_node whcn_template;
 | 
			
		||||
          union {
 | 
			
		||||
            struct whc_idxnode idxn;
 | 
			
		||||
            char pad[sizeof (struct whc_idxnode) + sizeof (struct whc_node *)];
 | 
			
		||||
          } template;
 | 
			
		||||
          template.idxn.headidx = 0;
 | 
			
		||||
          template.idxn.hist[0] = &whcn_template;
 | 
			
		||||
          whcn_template.serdata = ddsi_serdata_ref (oldn->serdata);
 | 
			
		||||
          struct whc_idxnode template;
 | 
			
		||||
          template.iid = idxn->iid;
 | 
			
		||||
          assert (oldn->seq < whcn->seq);
 | 
			
		||||
#endif
 | 
			
		||||
          TRACE (" del %p %"PRId64, (void *) oldn, oldn->seq);
 | 
			
		||||
          whc_delete_one (whc, oldn);
 | 
			
		||||
#ifndef NDEBUG
 | 
			
		||||
          assert (ddsrt_hh_lookup (whc->idx_hash, &template) == idxn);
 | 
			
		||||
          ddsi_serdata_unref (whcn_template.serdata);
 | 
			
		||||
#endif
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,7 +16,7 @@
 | 
			
		|||
#include "dds/ddsi/ddsi_tkmap.h"
 | 
			
		||||
#include "dds/ddsi/q_thread.h"
 | 
			
		||||
#include "dds/ddsi/q_xmsg.h"
 | 
			
		||||
#include "dds/ddsi/q_rhc.h"
 | 
			
		||||
#include "dds/ddsi/ddsi_rhc.h"
 | 
			
		||||
#include "dds/ddsi/ddsi_serdata.h"
 | 
			
		||||
#include "dds__stream.h"
 | 
			
		||||
#include "dds/ddsi/q_transmit.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -71,9 +71,9 @@ dds_return_t dds_write_ts (dds_entity_t writer, const void *data, dds_time_t tim
 | 
			
		|||
  return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static dds_return_t try_store (struct rhc *rhc, const struct proxy_writer_info *pwr_info, struct ddsi_serdata *payload, struct ddsi_tkmap_instance *tk, dds_duration_t *max_block_ms)
 | 
			
		||||
static dds_return_t try_store (struct ddsi_rhc *rhc, const struct ddsi_writer_info *pwr_info, struct ddsi_serdata *payload, struct ddsi_tkmap_instance *tk, dds_duration_t *max_block_ms)
 | 
			
		||||
{
 | 
			
		||||
  while (! rhc_store (rhc, pwr_info, payload, tk))
 | 
			
		||||
  while (! ddsi_rhc_store (rhc, pwr_info, payload, tk))
 | 
			
		||||
  {
 | 
			
		||||
    if (*max_block_ms > 0)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -98,8 +98,8 @@ static dds_return_t deliver_locally (struct writer *wr, struct ddsi_serdata *pay
 | 
			
		|||
    if (rdary[0])
 | 
			
		||||
    {
 | 
			
		||||
      dds_duration_t max_block_ms = wr->xqos->reliability.max_blocking_time;
 | 
			
		||||
      struct proxy_writer_info pwr_info;
 | 
			
		||||
      make_proxy_writer_info (&pwr_info, &wr->e, wr->xqos);
 | 
			
		||||
      struct ddsi_writer_info pwr_info;
 | 
			
		||||
      ddsi_make_writer_info (&pwr_info, &wr->e, wr->xqos);
 | 
			
		||||
      for (uint32_t i = 0; rdary[i]; i++) {
 | 
			
		||||
        DDS_CTRACE (&wr->e.gv->logconfig, "reader "PGUIDFMT"\n", PGUID (rdary[i]->e.guid));
 | 
			
		||||
        if ((ret = try_store (rdary[i]->rhc, &pwr_info, payload, tk, &max_block_ms)) != DDS_RETCODE_OK)
 | 
			
		||||
| 
						 | 
				
			
			@ -120,11 +120,11 @@ static dds_return_t deliver_locally (struct writer *wr, struct ddsi_serdata *pay
 | 
			
		|||
       reliable samples that are rejected are simply discarded. */
 | 
			
		||||
    ddsrt_avl_iter_t it;
 | 
			
		||||
    struct pwr_rd_match *m;
 | 
			
		||||
    struct proxy_writer_info pwr_info;
 | 
			
		||||
    struct ddsi_writer_info wrinfo;
 | 
			
		||||
    const struct ephash *gh = wr->e.gv->guid_hash;
 | 
			
		||||
    dds_duration_t max_block_ms = wr->xqos->reliability.max_blocking_time;
 | 
			
		||||
    ddsrt_mutex_unlock (&wr->rdary.rdary_lock);
 | 
			
		||||
    make_proxy_writer_info (&pwr_info, &wr->e, wr->xqos);
 | 
			
		||||
    ddsi_make_writer_info (&wrinfo, &wr->e, wr->xqos);
 | 
			
		||||
    ddsrt_mutex_lock (&wr->e.lock);
 | 
			
		||||
    for (m = ddsrt_avl_iter_first (&wr_local_readers_treedef, &wr->local_readers, &it); m != NULL; m = ddsrt_avl_iter_next (&it))
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -133,7 +133,7 @@ static dds_return_t deliver_locally (struct writer *wr, struct ddsi_serdata *pay
 | 
			
		|||
      {
 | 
			
		||||
        DDS_CTRACE (&wr->e.gv->logconfig, "reader-via-guid "PGUIDFMT"\n", PGUID (rd->e.guid));
 | 
			
		||||
        /* Copied the return value ignore from DDSI deliver_user_data () function. */
 | 
			
		||||
        if ((ret = try_store (rd->rhc, &pwr_info, payload, tk, &max_block_ms)) != DDS_RETCODE_OK)
 | 
			
		||||
        if ((ret = try_store (rd->rhc, &wrinfo, payload, tk, &max_block_ms)) != DDS_RETCODE_OK)
 | 
			
		||||
          break;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -51,34 +51,36 @@ static dds_return_t dds_writer_status_validate (uint32_t mask)
 | 
			
		|||
 | 
			
		||||
static void dds_writer_status_cb (void *ventity, const status_cb_data_t *data)
 | 
			
		||||
{
 | 
			
		||||
  struct dds_entity * const entity = ventity;
 | 
			
		||||
  dds_writer * const wr = ventity;
 | 
			
		||||
 | 
			
		||||
  /* When data is NULL, it means that the writer is deleted. */
 | 
			
		||||
  /* When data is NULL, it means that the DDSI reader is deleted. */
 | 
			
		||||
  if (data == NULL)
 | 
			
		||||
  {
 | 
			
		||||
    /* Release the initial claim that was done during the create. This
 | 
			
		||||
     * will indicate that further API deletion is now possible. */
 | 
			
		||||
    dds_handle_unpin (&entity->m_hdllink);
 | 
			
		||||
    ddsrt_mutex_lock (&wr->m_entity.m_mutex);
 | 
			
		||||
    wr->m_wr = NULL;
 | 
			
		||||
    ddsrt_cond_broadcast (&wr->m_entity.m_cond);
 | 
			
		||||
    ddsrt_mutex_unlock (&wr->m_entity.m_mutex);
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  struct dds_listener const * const lst = &entity->m_listener;
 | 
			
		||||
  struct dds_listener const * const lst = &wr->m_entity.m_listener;
 | 
			
		||||
  enum dds_status_id status_id = (enum dds_status_id) data->raw_status_id;
 | 
			
		||||
  bool invoke = false;
 | 
			
		||||
  void *vst = NULL;
 | 
			
		||||
  int32_t *reset[2] = { NULL, NULL };
 | 
			
		||||
 | 
			
		||||
  ddsrt_mutex_lock (&entity->m_observers_lock);
 | 
			
		||||
  while (entity->m_cb_count > 0)
 | 
			
		||||
    ddsrt_cond_wait (&entity->m_observers_cond, &entity->m_observers_lock);
 | 
			
		||||
  entity->m_cb_count++;
 | 
			
		||||
  /* FIXME: why wait if no listener is set? */
 | 
			
		||||
  ddsrt_mutex_lock (&wr->m_entity.m_observers_lock);
 | 
			
		||||
  while (wr->m_entity.m_cb_count > 0)
 | 
			
		||||
    ddsrt_cond_wait (&wr->m_entity.m_observers_cond, &wr->m_entity.m_observers_lock);
 | 
			
		||||
 | 
			
		||||
  /* Reset the status for possible Listener call.
 | 
			
		||||
   * When a listener is not called, the status will be set (again). */
 | 
			
		||||
  dds_entity_status_reset (entity, (status_mask_t) (1u << status_id));
 | 
			
		||||
  dds_entity_status_reset (&wr->m_entity, (status_mask_t) (1u << status_id));
 | 
			
		||||
 | 
			
		||||
  /* Update status metrics. */
 | 
			
		||||
  dds_writer * const wr = (dds_writer *) entity;
 | 
			
		||||
  switch (status_id)
 | 
			
		||||
  {
 | 
			
		||||
    case DDS_OFFERED_DEADLINE_MISSED_STATUS_ID: {
 | 
			
		||||
| 
						 | 
				
			
			@ -136,23 +138,31 @@ static void dds_writer_status_cb (void *ventity, const status_cb_data_t *data)
 | 
			
		|||
      assert (0);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (invoke)
 | 
			
		||||
  const uint32_t enabled = (ddsrt_atomic_ld32 (&wr->m_entity.m_status.m_status_and_mask) & ((1u << status_id) << SAM_ENABLED_SHIFT));
 | 
			
		||||
  if (enabled == 0)
 | 
			
		||||
  {
 | 
			
		||||
    ddsrt_mutex_unlock (&entity->m_observers_lock);
 | 
			
		||||
    dds_entity_invoke_listener(entity, status_id, vst);
 | 
			
		||||
    ddsrt_mutex_lock (&entity->m_observers_lock);
 | 
			
		||||
    /* Don't invoke listeners or set status flag if masked */
 | 
			
		||||
  }
 | 
			
		||||
  else if (invoke)
 | 
			
		||||
  {
 | 
			
		||||
    wr->m_entity.m_cb_pending_count++;
 | 
			
		||||
    wr->m_entity.m_cb_count++;
 | 
			
		||||
    ddsrt_mutex_unlock (&wr->m_entity.m_observers_lock);
 | 
			
		||||
    dds_entity_invoke_listener (&wr->m_entity, status_id, vst);
 | 
			
		||||
    ddsrt_mutex_lock (&wr->m_entity.m_observers_lock);
 | 
			
		||||
    wr->m_entity.m_cb_count--;
 | 
			
		||||
    wr->m_entity.m_cb_pending_count--;
 | 
			
		||||
    *reset[0] = 0;
 | 
			
		||||
    if (reset[1])
 | 
			
		||||
      *reset[1] = 0;
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
    dds_entity_status_set (entity, (status_mask_t) (1u << status_id));
 | 
			
		||||
    dds_entity_status_set (&wr->m_entity, (status_mask_t) (1u << status_id));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  entity->m_cb_count--;
 | 
			
		||||
  ddsrt_cond_broadcast (&entity->m_observers_cond);
 | 
			
		||||
  ddsrt_mutex_unlock (&entity->m_observers_lock);
 | 
			
		||||
  ddsrt_cond_broadcast (&wr->m_entity.m_observers_cond);
 | 
			
		||||
  ddsrt_mutex_unlock (&wr->m_entity.m_observers_lock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static uint32_t get_bandwidth_limit (dds_transport_priority_qospolicy_t transport_priority)
 | 
			
		||||
| 
						 | 
				
			
			@ -166,18 +176,32 @@ static uint32_t get_bandwidth_limit (dds_transport_priority_qospolicy_t transpor
 | 
			
		|||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static dds_return_t dds_writer_close (dds_entity *e) ddsrt_nonnull_all;
 | 
			
		||||
static void dds_writer_interrupt (dds_entity *e) ddsrt_nonnull_all;
 | 
			
		||||
 | 
			
		||||
static dds_return_t dds_writer_close (dds_entity *e)
 | 
			
		||||
static void dds_writer_interrupt (dds_entity *e)
 | 
			
		||||
{
 | 
			
		||||
  dds_writer * const wr = (dds_writer *) e;
 | 
			
		||||
  dds_return_t ret;
 | 
			
		||||
  thread_state_awake (lookup_thread_state (), &e->m_domain->gv);
 | 
			
		||||
  nn_xpack_send (wr->m_xp, false);
 | 
			
		||||
  if ((ret = delete_writer (&e->m_domain->gv, &e->m_guid)) < 0)
 | 
			
		||||
    ret = DDS_RETCODE_ERROR;
 | 
			
		||||
  struct q_globals * const gv = &e->m_domain->gv;
 | 
			
		||||
  thread_state_awake (lookup_thread_state (), gv);
 | 
			
		||||
  unblock_throttled_writer (gv, &e->m_guid);
 | 
			
		||||
  thread_state_asleep (lookup_thread_state ());
 | 
			
		||||
  return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void dds_writer_close (dds_entity *e) ddsrt_nonnull_all;
 | 
			
		||||
 | 
			
		||||
static void dds_writer_close (dds_entity *e)
 | 
			
		||||
{
 | 
			
		||||
  struct dds_writer * const wr = (struct dds_writer *) e;
 | 
			
		||||
  struct q_globals * const gv = &e->m_domain->gv;
 | 
			
		||||
  struct thread_state1 * const ts1 = lookup_thread_state ();
 | 
			
		||||
  thread_state_awake (ts1, gv);
 | 
			
		||||
  nn_xpack_send (wr->m_xp, false);
 | 
			
		||||
  (void) delete_writer (gv, &e->m_guid);
 | 
			
		||||
  thread_state_asleep (ts1);
 | 
			
		||||
 | 
			
		||||
  ddsrt_mutex_lock (&e->m_mutex);
 | 
			
		||||
  while (wr->m_wr != NULL)
 | 
			
		||||
    ddsrt_cond_wait (&e->m_cond, &e->m_mutex);
 | 
			
		||||
  ddsrt_mutex_unlock (&e->m_mutex);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static dds_return_t dds_writer_delete (dds_entity *e) ddsrt_nonnull_all;
 | 
			
		||||
| 
						 | 
				
			
			@ -190,12 +214,7 @@ static dds_return_t dds_writer_delete (dds_entity *e)
 | 
			
		|||
  thread_state_awake (lookup_thread_state (), &e->m_domain->gv);
 | 
			
		||||
  nn_xpack_free (wr->m_xp);
 | 
			
		||||
  thread_state_asleep (lookup_thread_state ());
 | 
			
		||||
  if ((ret = dds_delete (wr->m_topic->m_entity.m_hdllink.hdl)) == DDS_RETCODE_OK)
 | 
			
		||||
  {
 | 
			
		||||
    ret = dds_delete_impl (e->m_parent->m_hdllink.hdl, true);
 | 
			
		||||
    if (ret == DDS_RETCODE_BAD_PARAMETER)
 | 
			
		||||
      ret = DDS_RETCODE_OK;
 | 
			
		||||
  }
 | 
			
		||||
  ret = dds_delete (wr->m_topic->m_entity.m_hdllink.hdl);
 | 
			
		||||
  return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -238,6 +257,7 @@ static struct whc *make_whc (struct dds_domain *dom, const dds_qos_t *qos)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
const struct dds_entity_deriver dds_entity_deriver_writer = {
 | 
			
		||||
  .interrupt = dds_writer_interrupt,
 | 
			
		||||
  .close = dds_writer_close,
 | 
			
		||||
  .delete = dds_writer_delete,
 | 
			
		||||
  .set_qos = dds_writer_qos_set,
 | 
			
		||||
| 
						 | 
				
			
			@ -251,6 +271,7 @@ dds_entity_t dds_create_writer (dds_entity_t participant_or_publisher, dds_entit
 | 
			
		|||
  dds_writer *wr;
 | 
			
		||||
  dds_entity_t writer;
 | 
			
		||||
  dds_publisher *pub = NULL;
 | 
			
		||||
  dds_participant *pp;
 | 
			
		||||
  dds_topic *tp;
 | 
			
		||||
  dds_entity_t publisher;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -259,7 +280,7 @@ dds_entity_t dds_create_writer (dds_entity_t participant_or_publisher, dds_entit
 | 
			
		|||
    if ((rc = dds_entity_pin (participant_or_publisher, &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);
 | 
			
		||||
      publisher = dds_create_publisher (participant_or_publisher, qos, NULL);
 | 
			
		||||
    else
 | 
			
		||||
      publisher = participant_or_publisher;
 | 
			
		||||
    dds_entity_unpin (p_or_p);
 | 
			
		||||
| 
						 | 
				
			
			@ -274,9 +295,14 @@ dds_entity_t dds_create_writer (dds_entity_t participant_or_publisher, dds_entit
 | 
			
		|||
 | 
			
		||||
  if ((rc = dds_topic_lock (topic, &tp)) != DDS_RETCODE_OK)
 | 
			
		||||
    goto err_tp_lock;
 | 
			
		||||
 | 
			
		||||
  assert (tp->m_stopic);
 | 
			
		||||
  assert (pub->m_entity.m_domain == tp->m_entity.m_domain);
 | 
			
		||||
 | 
			
		||||
  pp = dds_entity_participant (&pub->m_entity);
 | 
			
		||||
  if (pp != dds_entity_participant (&tp->m_entity))
 | 
			
		||||
  {
 | 
			
		||||
    rc = DDS_RETCODE_BAD_PARAMETER;
 | 
			
		||||
    goto err_pp_mismatch;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /* Merge Topic & Publisher qos */
 | 
			
		||||
  wqos = dds_create_qos ();
 | 
			
		||||
| 
						 | 
				
			
			@ -304,34 +330,26 @@ dds_entity_t dds_create_writer (dds_entity_t participant_or_publisher, dds_entit
 | 
			
		|||
  wr->m_whc = make_whc (pub->m_entity.m_domain, wqos);
 | 
			
		||||
  wr->whc_batch = pub->m_entity.m_domain->gv.config.whc_batch;
 | 
			
		||||
 | 
			
		||||
  /* Extra claim of this writer to make sure that the delete waits until DDSI
 | 
			
		||||
   * has deleted its writer as well. This can be known through the callback. */
 | 
			
		||||
  dds_handle_repin (&wr->m_entity.m_hdllink);
 | 
			
		||||
 | 
			
		||||
  ddsrt_mutex_unlock (&tp->m_entity.m_mutex);
 | 
			
		||||
  ddsrt_mutex_unlock (&pub->m_entity.m_mutex);
 | 
			
		||||
 | 
			
		||||
  thread_state_awake (lookup_thread_state (), &pub->m_entity.m_domain->gv);
 | 
			
		||||
  rc = new_writer (&wr->m_wr, &wr->m_entity.m_domain->gv, &wr->m_entity.m_guid, NULL, &pub->m_entity.m_participant->m_guid, tp->m_stopic, wqos, wr->m_whc, dds_writer_status_cb, wr);
 | 
			
		||||
  ddsrt_mutex_lock (&pub->m_entity.m_mutex);
 | 
			
		||||
  ddsrt_mutex_lock (&tp->m_entity.m_mutex);
 | 
			
		||||
  rc = new_writer (&wr->m_wr, &wr->m_entity.m_domain->gv, &wr->m_entity.m_guid, NULL, &pp->m_entity.m_guid, tp->m_stopic, wqos, wr->m_whc, dds_writer_status_cb, wr);
 | 
			
		||||
  assert(rc == DDS_RETCODE_OK);
 | 
			
		||||
  thread_state_asleep (lookup_thread_state ());
 | 
			
		||||
 | 
			
		||||
  wr->m_entity.m_iid = get_entity_instance_id (&wr->m_entity.m_domain->gv, &wr->m_entity.m_guid);
 | 
			
		||||
  dds_entity_register_child (&pub->m_entity, &wr->m_entity);
 | 
			
		||||
 | 
			
		||||
  dds_entity_init_complete (&wr->m_entity);
 | 
			
		||||
  dds_topic_unlock (tp);
 | 
			
		||||
  dds_publisher_unlock (pub);
 | 
			
		||||
  return writer;
 | 
			
		||||
 | 
			
		||||
err_bad_qos:
 | 
			
		||||
err_pp_mismatch:
 | 
			
		||||
  dds_topic_unlock (tp);
 | 
			
		||||
err_tp_lock:
 | 
			
		||||
  dds_publisher_unlock (pub);
 | 
			
		||||
  if ((pub->m_entity.m_flags & DDS_ENTITY_IMPLICIT) != 0){
 | 
			
		||||
    (void )dds_delete (publisher);
 | 
			
		||||
  }
 | 
			
		||||
  if ((pub->m_entity.m_flags & DDS_ENTITY_IMPLICIT) != 0)
 | 
			
		||||
    (void) dds_delete (publisher);
 | 
			
		||||
  return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,6 +20,7 @@ set(ddsc_test_sources
 | 
			
		|||
    "builtin_topics.c"
 | 
			
		||||
    "config.c"
 | 
			
		||||
    "dispose.c"
 | 
			
		||||
    "domain.c"
 | 
			
		||||
    "entity_api.c"
 | 
			
		||||
    "entity_hierarchy.c"
 | 
			
		||||
    "entity_status.c"
 | 
			
		||||
| 
						 | 
				
			
			@ -30,6 +31,7 @@ set(ddsc_test_sources
 | 
			
		|||
    "publisher.c"
 | 
			
		||||
    "qos.c"
 | 
			
		||||
    "querycondition.c"
 | 
			
		||||
    "guardcondition.c"
 | 
			
		||||
    "readcondition.c"
 | 
			
		||||
    "reader.c"
 | 
			
		||||
    "reader_iterator.c"
 | 
			
		||||
| 
						 | 
				
			
			@ -45,6 +47,7 @@ set(ddsc_test_sources
 | 
			
		|||
    "unregister.c"
 | 
			
		||||
    "unsupported.c"
 | 
			
		||||
    "waitset.c"
 | 
			
		||||
    "waitset_torture.c"
 | 
			
		||||
    "write.c"
 | 
			
		||||
    "writer.c")
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -308,3 +308,35 @@ CU_Test(ddsc_builtin_topics, builtin_qos, .init = setup, .fini = teardown)
 | 
			
		|||
  CU_ASSERT_FATAL(dds_sub_subscriber > 0);
 | 
			
		||||
  check_default_qos_of_builtin_entity(dds_sub_subscriber, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
CU_Test(ddsc_builtin_topics, read_nothing)
 | 
			
		||||
{
 | 
			
		||||
  dds_entity_t pp;
 | 
			
		||||
  dds_entity_t rd;
 | 
			
		||||
  dds_return_t ret;
 | 
			
		||||
  dds_sample_info_t si;
 | 
			
		||||
  void *raw1, *raw2;
 | 
			
		||||
  int32_t n1, n2;
 | 
			
		||||
 | 
			
		||||
  pp = dds_create_participant (DDS_DOMAIN_DEFAULT, NULL, NULL);
 | 
			
		||||
  CU_ASSERT_FATAL (pp > 0);
 | 
			
		||||
  rd = dds_create_reader (pp, DDS_BUILTIN_TOPIC_DCPSSUBSCRIPTION, NULL, NULL);
 | 
			
		||||
  CU_ASSERT_FATAL (rd > 0);
 | 
			
		||||
 | 
			
		||||
  /* Can't guarantee there's no other process around with a publication, but
 | 
			
		||||
     we can take until nothing remains.  The point is checking handling of
 | 
			
		||||
     freeing memory when a loan was outstanding, memory had to be allocated,
 | 
			
		||||
     and subsequently had to be freed because of an absence of data. */
 | 
			
		||||
  raw1 = raw2 = NULL;
 | 
			
		||||
  n1 = dds_take (rd, &raw1, &si, 1, 1);
 | 
			
		||||
  CU_ASSERT_FATAL (n1 >= 0);
 | 
			
		||||
  n2 = dds_take (rd, &raw2, &si, 1, 1);
 | 
			
		||||
  CU_ASSERT_FATAL (n2 >= 0);
 | 
			
		||||
  ret = dds_return_loan (rd, &raw1, n1);
 | 
			
		||||
  CU_ASSERT_FATAL (ret == 0);
 | 
			
		||||
  ret = dds_return_loan (rd, &raw2, n2);
 | 
			
		||||
  CU_ASSERT_FATAL (ret == 0);
 | 
			
		||||
  
 | 
			
		||||
  ret = dds_delete (pp);
 | 
			
		||||
  CU_ASSERT_FATAL (ret == 0);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -75,3 +75,46 @@ CU_Test(ddsc_config, simple_udp, .init = ddsrt_init, .fini = ddsrt_fini) {
 | 
			
		|||
 | 
			
		||||
    dds_delete(participant);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
CU_Test(ddsc_config, user_config, .init = ddsrt_init, .fini = ddsrt_fini) {
 | 
			
		||||
 | 
			
		||||
    CU_ASSERT_FATAL(dds_create_domain(1,
 | 
			
		||||
         "<"DDS_PROJECT_NAME"><Domain><Id>any</Id></Domain>"
 | 
			
		||||
           "<DDSI2E><Internal><MaxParticipants>2</MaxParticipants></Internal></DDSI2E>"
 | 
			
		||||
         "</"DDS_PROJECT_NAME">") == DDS_RETCODE_OK);
 | 
			
		||||
 | 
			
		||||
    dds_entity_t participant_1;
 | 
			
		||||
    dds_entity_t participant_2;
 | 
			
		||||
    dds_entity_t participant_3;
 | 
			
		||||
 | 
			
		||||
    participant_1 = dds_create_participant(1, NULL, NULL);
 | 
			
		||||
 | 
			
		||||
    CU_ASSERT_FATAL(participant_1 > 0);
 | 
			
		||||
 | 
			
		||||
    participant_2 = dds_create_participant(1, NULL, NULL);
 | 
			
		||||
 | 
			
		||||
    CU_ASSERT_FATAL(participant_2 > 0);
 | 
			
		||||
 | 
			
		||||
    participant_3 = dds_create_participant(1, NULL, NULL);
 | 
			
		||||
 | 
			
		||||
    CU_ASSERT(participant_3 <= 0);
 | 
			
		||||
 | 
			
		||||
    dds_delete(participant_3);
 | 
			
		||||
    dds_delete(participant_2);
 | 
			
		||||
    dds_delete(participant_1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
CU_Test(ddsc_config, incorrect_config, .init = ddsrt_init, .fini = ddsrt_fini) {
 | 
			
		||||
 | 
			
		||||
    CU_ASSERT_FATAL(dds_create_domain(1, NULL) == DDS_RETCODE_BAD_PARAMETER);
 | 
			
		||||
    CU_ASSERT_FATAL(dds_create_domain(1, "<CycloneDDS incorrect XML") != DDS_RETCODE_OK);
 | 
			
		||||
    CU_ASSERT_FATAL(dds_create_domain(DDS_DOMAIN_DEFAULT,
 | 
			
		||||
         "<"DDS_PROJECT_NAME"><Domain><Id>any</Id></Domain>"
 | 
			
		||||
           "<DDSI2E><Internal><MaxParticipants>2</MaxParticipants></Internal></DDSI2E>"
 | 
			
		||||
         "</"DDS_PROJECT_NAME">") == DDS_RETCODE_BAD_PARAMETER);
 | 
			
		||||
    CU_ASSERT_FATAL(dds_create_domain(2,
 | 
			
		||||
         "<"DDS_PROJECT_NAME"><Domain><Id>any</Id></Domain>"
 | 
			
		||||
           "<DDSI2E><Internal><MaxParticipants>2</MaxParticipants></Internal></DDSI2E>"
 | 
			
		||||
         "</"DDS_PROJECT_NAME">") == DDS_RETCODE_OK);
 | 
			
		||||
    CU_ASSERT_FATAL(dds_create_domain(2, "") == DDS_RETCODE_PRECONDITION_NOT_MET);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										142
									
								
								src/core/ddsc/tests/domain.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										142
									
								
								src/core/ddsc/tests/domain.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,142 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright(c) 2019 ADLINK Technology Limited and others
 | 
			
		||||
 *
 | 
			
		||||
 * This program and the accompanying materials are made available under the
 | 
			
		||||
 * terms of the Eclipse Public License v. 2.0 which is available at
 | 
			
		||||
 * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
 | 
			
		||||
 * v. 1.0 which is available at
 | 
			
		||||
 * http://www.eclipse.org/org/documents/edl-v10.php.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
 | 
			
		||||
#include "dds/dds.h"
 | 
			
		||||
#include "CUnit/Test.h"
 | 
			
		||||
#include "config_env.h"
 | 
			
		||||
#include "dds/version.h"
 | 
			
		||||
#include "dds/ddsrt/environ.h"
 | 
			
		||||
 | 
			
		||||
CU_Test(ddsc_domain, get_domainid)
 | 
			
		||||
{
 | 
			
		||||
  dds_entity_t pp, d, x;
 | 
			
		||||
  dds_return_t rc;
 | 
			
		||||
  uint32_t did;
 | 
			
		||||
  pp = dds_create_participant (0, NULL, NULL);
 | 
			
		||||
  CU_ASSERT_FATAL (pp > 0);
 | 
			
		||||
  d = dds_get_parent (pp);
 | 
			
		||||
  CU_ASSERT_FATAL (d > 0);
 | 
			
		||||
  x = dds_get_parent (d);
 | 
			
		||||
  CU_ASSERT_FATAL (x == DDS_CYCLONEDDS_HANDLE);
 | 
			
		||||
  x = dds_get_parent (x);
 | 
			
		||||
  CU_ASSERT_FATAL (x == 0);
 | 
			
		||||
 | 
			
		||||
  rc = dds_get_domainid (pp, &did);
 | 
			
		||||
  CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
 | 
			
		||||
  CU_ASSERT_FATAL (did == 0);
 | 
			
		||||
  rc = dds_get_domainid (d, &did);
 | 
			
		||||
  CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
 | 
			
		||||
  CU_ASSERT_FATAL (did == 0);
 | 
			
		||||
  rc = dds_get_domainid (DDS_CYCLONEDDS_HANDLE, &did);
 | 
			
		||||
  CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
 | 
			
		||||
  CU_ASSERT_FATAL (did == DDS_DOMAIN_DEFAULT);
 | 
			
		||||
  rc = dds_delete (pp);
 | 
			
		||||
  CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
CU_Test(ddsc_domain, delete_domain0)
 | 
			
		||||
{
 | 
			
		||||
  dds_entity_t pp[3], d[3];
 | 
			
		||||
  dds_return_t rc;
 | 
			
		||||
  uint32_t did;
 | 
			
		||||
  for (dds_domainid_t i = 0; i < (dds_domainid_t) (sizeof (pp) / sizeof (pp[0])); i++)
 | 
			
		||||
  {
 | 
			
		||||
    pp[i] = dds_create_participant (0, NULL, NULL);
 | 
			
		||||
    CU_ASSERT_FATAL (pp[i] > 0);
 | 
			
		||||
    d[i] = dds_get_parent (pp[i]);
 | 
			
		||||
    CU_ASSERT_FATAL (d[i] > 0);
 | 
			
		||||
    if (i > 0)
 | 
			
		||||
      CU_ASSERT_FATAL (d[i] == d[i-1]);
 | 
			
		||||
  }
 | 
			
		||||
  rc = dds_delete (pp[0]);
 | 
			
		||||
  CU_ASSERT_FATAL (rc == 0);
 | 
			
		||||
  rc = dds_get_domainid (pp[0], &did);
 | 
			
		||||
  CU_ASSERT_FATAL (rc == DDS_RETCODE_BAD_PARAMETER);
 | 
			
		||||
  for (size_t i = 1; i < sizeof (pp) / sizeof (pp[0]); i++)
 | 
			
		||||
  {
 | 
			
		||||
    rc = dds_get_domainid (pp[i], &did);
 | 
			
		||||
    CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
 | 
			
		||||
    CU_ASSERT_FATAL (did == 0);
 | 
			
		||||
  }
 | 
			
		||||
  rc = dds_delete (d[1]);
 | 
			
		||||
  CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
 | 
			
		||||
  /* Deleting the domain should delete all participants in it as well,
 | 
			
		||||
     and as there is only a single domain in this test, that should
 | 
			
		||||
     de-initialize the library.
 | 
			
		||||
 | 
			
		||||
     A non-initialized library returns PRECONDITION_NOT_MET; an
 | 
			
		||||
     initialized one given an invalid handle returns BAD_PARAMETER,
 | 
			
		||||
     so we can distinguish the two cases. */
 | 
			
		||||
  rc = dds_get_domainid (pp[1], &did);
 | 
			
		||||
  CU_ASSERT_FATAL (rc == DDS_RETCODE_PRECONDITION_NOT_MET);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
CU_Test(ddsc_domain, delete_domainM)
 | 
			
		||||
{
 | 
			
		||||
  dds_entity_t pp[3], d[3], x;
 | 
			
		||||
  dds_return_t rc;
 | 
			
		||||
  uint32_t did;
 | 
			
		||||
  for (dds_domainid_t i = 0; i < (dds_domainid_t) (sizeof (pp) / sizeof (pp[0])); i++)
 | 
			
		||||
  {
 | 
			
		||||
    pp[i] = dds_create_participant (i, NULL, NULL);
 | 
			
		||||
    CU_ASSERT_FATAL (pp[i] > 0);
 | 
			
		||||
    d[i] = dds_get_parent (pp[i]);
 | 
			
		||||
    CU_ASSERT_FATAL (d[i] > 0);
 | 
			
		||||
    for (dds_domainid_t j = 0; j < i; j++)
 | 
			
		||||
      CU_ASSERT_FATAL (d[i] != d[j]);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /* deleting participant 0 should tear down domain 0, but nothing else */
 | 
			
		||||
  rc = dds_delete (pp[0]);
 | 
			
		||||
  CU_ASSERT_FATAL (rc == 0);
 | 
			
		||||
  rc = dds_get_domainid (pp[0], &did);
 | 
			
		||||
  CU_ASSERT_FATAL (rc == DDS_RETCODE_BAD_PARAMETER);
 | 
			
		||||
  rc = dds_get_domainid (d[0], &did);
 | 
			
		||||
  CU_ASSERT_FATAL (rc == DDS_RETCODE_BAD_PARAMETER);
 | 
			
		||||
 | 
			
		||||
  /* deleting domain should delete participant 1, but leave domain 2 alone */
 | 
			
		||||
  rc = dds_delete (d[1]);
 | 
			
		||||
  CU_ASSERT_FATAL (rc == 0);
 | 
			
		||||
  rc = dds_get_domainid (pp[1], &did);
 | 
			
		||||
  CU_ASSERT_FATAL (rc == DDS_RETCODE_BAD_PARAMETER);
 | 
			
		||||
  x = dds_get_parent (pp[2]);
 | 
			
		||||
  CU_ASSERT_FATAL (x == d[2]);
 | 
			
		||||
 | 
			
		||||
  /* after deleting participant 2, everything should be gone */
 | 
			
		||||
  rc = dds_delete (pp[2]);
 | 
			
		||||
  CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
 | 
			
		||||
  rc = dds_get_domainid (pp[1], &did);
 | 
			
		||||
  CU_ASSERT_FATAL (rc == DDS_RETCODE_PRECONDITION_NOT_MET);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
CU_Test(ddsc_domain, delete_cyclonedds)
 | 
			
		||||
{
 | 
			
		||||
  dds_entity_t pp[3], d[3];
 | 
			
		||||
  dds_return_t rc;
 | 
			
		||||
  uint32_t did;
 | 
			
		||||
  for (dds_domainid_t i = 0; i < (dds_domainid_t) (sizeof (pp) / sizeof (pp[0])); i++)
 | 
			
		||||
  {
 | 
			
		||||
    pp[i] = dds_create_participant (i, NULL, NULL);
 | 
			
		||||
    CU_ASSERT_FATAL (pp[i] > 0);
 | 
			
		||||
    d[i] = dds_get_parent (pp[i]);
 | 
			
		||||
    CU_ASSERT_FATAL (d[i] > 0);
 | 
			
		||||
    for (dds_domainid_t j = 0; j < i; j++)
 | 
			
		||||
      CU_ASSERT_FATAL (d[i] != d[j]);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /* deleting participant 0 should tear down domain 0, but nothing else */
 | 
			
		||||
  rc = dds_delete (DDS_CYCLONEDDS_HANDLE);
 | 
			
		||||
  CU_ASSERT_FATAL (rc == 0);
 | 
			
		||||
  rc = dds_get_domainid (pp[0], &did);
 | 
			
		||||
  CU_ASSERT_FATAL (rc == DDS_RETCODE_PRECONDITION_NOT_MET);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -290,9 +290,12 @@ CU_Test(ddsc_entity, get_entities, .init = create_entity, .fini = delete_entity)
 | 
			
		|||
    par = dds_get_parent (0);
 | 
			
		||||
    CU_ASSERT_EQUAL_FATAL(par, DDS_RETCODE_BAD_PARAMETER);
 | 
			
		||||
 | 
			
		||||
    /* Get Parent, a participant doesn't have a parent. */
 | 
			
		||||
    /* Get Parent, a participant always has a parent (the domain). */
 | 
			
		||||
    par = dds_get_parent (entity);
 | 
			
		||||
    CU_ASSERT_EQUAL_FATAL(par, DDS_ENTITY_NIL);
 | 
			
		||||
    CU_ASSERT_NOT_EQUAL_FATAL(par, DDS_HANDLE_NIL);
 | 
			
		||||
    /* The domain has a parent: the pseudo-entity for the library */
 | 
			
		||||
    par = dds_get_parent (par);
 | 
			
		||||
    CU_ASSERT_EQUAL_FATAL(par, DDS_CYCLONEDDS_HANDLE);
 | 
			
		||||
 | 
			
		||||
    /* ---------- Get Participant ------------ */
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -313,7 +313,11 @@ CU_Test(ddsc_entity_get_parent, participant, .init=hierarchy_init, .fini=hierarc
 | 
			
		|||
{
 | 
			
		||||
    dds_entity_t parent;
 | 
			
		||||
    parent = dds_get_parent(g_participant);
 | 
			
		||||
    CU_ASSERT_EQUAL_FATAL(parent, DDS_ENTITY_NIL);
 | 
			
		||||
    CU_ASSERT_NOT_EQUAL_FATAL(parent, DDS_ENTITY_NIL);
 | 
			
		||||
    parent = dds_get_parent(parent);
 | 
			
		||||
    CU_ASSERT_NOT_EQUAL_FATAL(parent, DDS_ENTITY_NIL);
 | 
			
		||||
    parent = dds_get_parent(parent);
 | 
			
		||||
    CU_ASSERT_NOT_EQUAL_FATAL(parent, DDS_CYCLONEDDS_HANDLE);
 | 
			
		||||
}
 | 
			
		||||
/*************************************************************************************************/
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -362,13 +366,15 @@ CU_Test(ddsc_entity_get_children, null, .init=hierarchy_init, .fini=hierarchy_fi
 | 
			
		|||
/*************************************************************************************************/
 | 
			
		||||
 | 
			
		||||
/*************************************************************************************************/
 | 
			
		||||
#if SIZE_MAX > INT32_MAX
 | 
			
		||||
CU_Test(ddsc_entity_get_children, invalid_size, .init=hierarchy_init, .fini=hierarchy_fini)
 | 
			
		||||
{
 | 
			
		||||
    dds_return_t ret;
 | 
			
		||||
    dds_entity_t child;
 | 
			
		||||
    ret = dds_get_children(g_participant, &child, INT32_MAX);
 | 
			
		||||
    ret = dds_get_children(g_participant, &child, SIZE_MAX);
 | 
			
		||||
    CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER);
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
/*************************************************************************************************/
 | 
			
		||||
 | 
			
		||||
/*************************************************************************************************/
 | 
			
		||||
| 
						 | 
				
			
			@ -866,9 +872,8 @@ CU_Test(ddsc_entity_get_children, implicit_publisher)
 | 
			
		|||
    dds_delete(writer);
 | 
			
		||||
 | 
			
		||||
    ret = dds_get_children(participant, child2, 2);
 | 
			
		||||
    CU_ASSERT_EQUAL_FATAL(ret, 2);
 | 
			
		||||
    CU_ASSERT_EQUAL_FATAL(ret, 1);
 | 
			
		||||
    CU_ASSERT_FATAL( (child2[0] == child[0]) || (child2[0] == child[1]) );
 | 
			
		||||
    CU_ASSERT_FATAL( (child2[1] == child[0]) || (child2[1] == child[1]) );
 | 
			
		||||
 | 
			
		||||
    dds_delete(topic);
 | 
			
		||||
    dds_delete(participant);
 | 
			
		||||
| 
						 | 
				
			
			@ -911,9 +916,8 @@ CU_Test(ddsc_entity_get_children, implicit_subscriber)
 | 
			
		|||
    dds_delete(reader);
 | 
			
		||||
 | 
			
		||||
    ret = dds_get_children(participant, child2, 2);
 | 
			
		||||
    CU_ASSERT_EQUAL_FATAL(ret, 2);
 | 
			
		||||
    CU_ASSERT_EQUAL_FATAL(ret, 1);
 | 
			
		||||
    CU_ASSERT_FATAL( (child2[0] == child[0]) || (child2[0] == child[1]) );
 | 
			
		||||
    CU_ASSERT_FATAL( (child2[1] == child[0]) || (child2[1] == child[1]) );
 | 
			
		||||
 | 
			
		||||
    dds_delete(topic);
 | 
			
		||||
    dds_delete(participant);
 | 
			
		||||
| 
						 | 
				
			
			@ -947,7 +951,7 @@ CU_Test(ddsc_entity_get_parent, implicit_publisher)
 | 
			
		|||
    dds_delete(writer);
 | 
			
		||||
 | 
			
		||||
    ret = dds_delete(parent);
 | 
			
		||||
    CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
 | 
			
		||||
    CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER);
 | 
			
		||||
    dds_delete(participant);
 | 
			
		||||
}
 | 
			
		||||
/*************************************************************************************************/
 | 
			
		||||
| 
						 | 
				
			
			@ -978,7 +982,7 @@ CU_Test(ddsc_entity_get_parent, implicit_subscriber)
 | 
			
		|||
    dds_delete(reader);
 | 
			
		||||
 | 
			
		||||
    ret = dds_delete(parent);
 | 
			
		||||
    CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
 | 
			
		||||
    CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER);
 | 
			
		||||
    dds_delete(participant);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										187
									
								
								src/core/ddsc/tests/guardcondition.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										187
									
								
								src/core/ddsc/tests/guardcondition.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,187 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
 | 
			
		||||
 *
 | 
			
		||||
 * This program and the accompanying materials are made available under the
 | 
			
		||||
 * terms of the Eclipse Public License v. 2.0 which is available at
 | 
			
		||||
 * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
 | 
			
		||||
 * v. 1.0 which is available at
 | 
			
		||||
 * http://www.eclipse.org/org/documents/edl-v10.php.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
 | 
			
		||||
#include "dds/dds.h"
 | 
			
		||||
#include "CUnit/Theory.h"
 | 
			
		||||
#include "RoundTrip.h"
 | 
			
		||||
 | 
			
		||||
#include "dds/ddsrt/cdtors.h"
 | 
			
		||||
#include "dds/ddsrt/misc.h"
 | 
			
		||||
#include "dds/ddsrt/process.h"
 | 
			
		||||
#include "dds/ddsrt/threads.h"
 | 
			
		||||
#include "dds/ddsrt/atomics.h"
 | 
			
		||||
#include "dds/ddsrt/time.h"
 | 
			
		||||
 | 
			
		||||
CU_Test (ddsc_guardcond_create, cyclonedds)
 | 
			
		||||
{
 | 
			
		||||
  dds_entity_t gc;
 | 
			
		||||
  dds_return_t rc;
 | 
			
		||||
  /* Expect an uninitialised library */
 | 
			
		||||
  rc = dds_get_parent (DDS_CYCLONEDDS_HANDLE);
 | 
			
		||||
  CU_ASSERT_FATAL (rc == DDS_RETCODE_PRECONDITION_NOT_MET);
 | 
			
		||||
  gc = dds_create_guardcondition (DDS_CYCLONEDDS_HANDLE);
 | 
			
		||||
  CU_ASSERT_FATAL (gc > 0);
 | 
			
		||||
  rc = dds_delete (DDS_CYCLONEDDS_HANDLE);
 | 
			
		||||
  CU_ASSERT_FATAL (rc == 0);
 | 
			
		||||
  /* And the same afterward */
 | 
			
		||||
  rc = dds_get_parent (DDS_CYCLONEDDS_HANDLE);
 | 
			
		||||
  CU_ASSERT_FATAL (rc == DDS_RETCODE_PRECONDITION_NOT_MET);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
CU_Test (ddsc_guardcond_create, domain)
 | 
			
		||||
{
 | 
			
		||||
  dds_entity_t par, dom, gc;
 | 
			
		||||
  dds_return_t rc;
 | 
			
		||||
  par = dds_create_participant (0, NULL, NULL);
 | 
			
		||||
  CU_ASSERT_FATAL (par > 0);
 | 
			
		||||
  dom = dds_get_parent (par);
 | 
			
		||||
  CU_ASSERT_FATAL (dom > 0);
 | 
			
		||||
  gc = dds_create_guardcondition (dom);
 | 
			
		||||
  CU_ASSERT_FATAL (gc > 0);
 | 
			
		||||
  rc = dds_delete (dom);
 | 
			
		||||
  CU_ASSERT_FATAL (rc == 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
CU_Test (ddsc_guardcond_create, participant)
 | 
			
		||||
{
 | 
			
		||||
  dds_entity_t par, gc;
 | 
			
		||||
  dds_return_t rc;
 | 
			
		||||
  par = dds_create_participant (0, NULL, NULL);
 | 
			
		||||
  CU_ASSERT_FATAL (par > 0);
 | 
			
		||||
  gc = dds_create_guardcondition (par);
 | 
			
		||||
  CU_ASSERT_FATAL (gc > 0);
 | 
			
		||||
  rc = dds_delete (par);
 | 
			
		||||
  CU_ASSERT_FATAL (rc == 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
CU_Test (ddsc_guardcond, set_trigger)
 | 
			
		||||
{
 | 
			
		||||
  dds_entity_t par, gc;
 | 
			
		||||
  dds_return_t rc;
 | 
			
		||||
  bool trig;
 | 
			
		||||
  par = dds_create_participant (0, NULL, NULL);
 | 
			
		||||
  CU_ASSERT_FATAL (par > 0);
 | 
			
		||||
  gc = dds_create_guardcondition (par);
 | 
			
		||||
  CU_ASSERT_FATAL (gc > 0);
 | 
			
		||||
  rc = dds_read_guardcondition (gc, &trig);
 | 
			
		||||
  CU_ASSERT_FATAL (rc == 0);
 | 
			
		||||
  CU_ASSERT (!trig);
 | 
			
		||||
  rc = dds_set_guardcondition (gc, true);
 | 
			
		||||
  CU_ASSERT_FATAL (rc == 0);
 | 
			
		||||
  rc = dds_read_guardcondition (gc, &trig);
 | 
			
		||||
  CU_ASSERT_FATAL (rc == 0);
 | 
			
		||||
  CU_ASSERT (trig);
 | 
			
		||||
  rc = dds_delete (par);
 | 
			
		||||
  CU_ASSERT_FATAL (rc == 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
CU_Test (ddsc_guardcond, take_trigger)
 | 
			
		||||
{
 | 
			
		||||
  dds_entity_t par, gc;
 | 
			
		||||
  dds_return_t rc;
 | 
			
		||||
  bool trig;
 | 
			
		||||
  par = dds_create_participant (0, NULL, NULL);
 | 
			
		||||
  CU_ASSERT_FATAL (par > 0);
 | 
			
		||||
  gc = dds_create_guardcondition (par);
 | 
			
		||||
  CU_ASSERT_FATAL (gc > 0);
 | 
			
		||||
  rc = dds_read_guardcondition (gc, &trig);
 | 
			
		||||
  CU_ASSERT_FATAL (rc == 0);
 | 
			
		||||
  CU_ASSERT (!trig);
 | 
			
		||||
  rc = dds_set_guardcondition (gc, true);
 | 
			
		||||
  CU_ASSERT_FATAL (rc == 0);
 | 
			
		||||
  rc = dds_take_guardcondition (gc, &trig);
 | 
			
		||||
  CU_ASSERT_FATAL (rc == 0);
 | 
			
		||||
  CU_ASSERT (trig);
 | 
			
		||||
  rc = dds_read_guardcondition (gc, &trig);
 | 
			
		||||
  CU_ASSERT_FATAL (rc == 0);
 | 
			
		||||
  CU_ASSERT (!trig);
 | 
			
		||||
  rc = dds_delete (par);
 | 
			
		||||
  CU_ASSERT_FATAL (rc == 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
CU_Test (ddsc_guardcond, waitset)
 | 
			
		||||
{
 | 
			
		||||
  dds_entity_t par, gc, ws;
 | 
			
		||||
  dds_attach_t xs[1];
 | 
			
		||||
  dds_return_t rc;
 | 
			
		||||
  par = dds_create_participant (0, NULL, NULL);
 | 
			
		||||
  CU_ASSERT_FATAL (par > 0);
 | 
			
		||||
  gc = dds_create_guardcondition (par);
 | 
			
		||||
  CU_ASSERT_FATAL (gc > 0);
 | 
			
		||||
  ws = dds_create_waitset (par);
 | 
			
		||||
  CU_ASSERT_FATAL (ws > 0);
 | 
			
		||||
  rc = dds_waitset_attach (ws, gc, gc);
 | 
			
		||||
  CU_ASSERT_FATAL (rc == 0);
 | 
			
		||||
  /* guard cond not triggered: waitset should return 0 */
 | 
			
		||||
  rc = dds_waitset_wait (ws, xs, 1, 0);
 | 
			
		||||
  CU_ASSERT (rc == 0);
 | 
			
		||||
  rc = dds_set_guardcondition (gc, true);
 | 
			
		||||
  CU_ASSERT_FATAL (rc == 0);
 | 
			
		||||
  /* guard triggered: waitset should return it */
 | 
			
		||||
  rc = dds_waitset_wait (ws, xs, 1, 0);
 | 
			
		||||
  CU_ASSERT (rc == 1);
 | 
			
		||||
  CU_ASSERT (xs[0] == gc);
 | 
			
		||||
  rc = dds_delete (par);
 | 
			
		||||
  CU_ASSERT_FATAL (rc == 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct guardcond_thread_arg {
 | 
			
		||||
  dds_entity_t gc;
 | 
			
		||||
  dds_return_t ret;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static uint32_t guardcond_thread (void *varg)
 | 
			
		||||
{
 | 
			
		||||
  struct guardcond_thread_arg *arg = varg;
 | 
			
		||||
  /* 200ms sleep is hopefully always long enough for the main thread to
 | 
			
		||||
     enter wait() and block; a further 1800ms (see wait call) similarly
 | 
			
		||||
     for the guard condition to actually trigger it. */
 | 
			
		||||
  dds_sleepfor (DDS_MSECS (200));
 | 
			
		||||
  arg->ret = dds_set_guardcondition (arg->gc, true);
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
CU_Test (ddsc_guardcond, waitset_thread)
 | 
			
		||||
{
 | 
			
		||||
  dds_entity_t par, gc, ws;
 | 
			
		||||
  dds_attach_t xs[1];
 | 
			
		||||
  dds_return_t rc;
 | 
			
		||||
  ddsrt_thread_t tid;
 | 
			
		||||
  ddsrt_threadattr_t tattr;
 | 
			
		||||
 | 
			
		||||
  par = dds_create_participant (0, NULL, NULL);
 | 
			
		||||
  CU_ASSERT_FATAL (par > 0);
 | 
			
		||||
  gc = dds_create_guardcondition (par);
 | 
			
		||||
  CU_ASSERT_FATAL (gc > 0);
 | 
			
		||||
  ws = dds_create_waitset (par);
 | 
			
		||||
  CU_ASSERT_FATAL (ws > 0);
 | 
			
		||||
  rc = dds_waitset_attach (ws, gc, gc);
 | 
			
		||||
  CU_ASSERT_FATAL (rc == 0);
 | 
			
		||||
 | 
			
		||||
  struct guardcond_thread_arg arg = { .gc = gc };
 | 
			
		||||
  ddsrt_threadattr_init (&tattr);
 | 
			
		||||
  rc = ddsrt_thread_create (&tid, "guardcond_thread", &tattr, guardcond_thread, &arg);
 | 
			
		||||
  CU_ASSERT_FATAL (rc == 0);
 | 
			
		||||
 | 
			
		||||
  rc = dds_waitset_wait (ws, xs, 1, DDS_SECS (2));
 | 
			
		||||
  CU_ASSERT (rc == 1);
 | 
			
		||||
  CU_ASSERT (xs[0] == gc);
 | 
			
		||||
 | 
			
		||||
  rc = ddsrt_thread_join (tid, NULL);
 | 
			
		||||
  CU_ASSERT_FATAL (rc == 0);
 | 
			
		||||
  CU_ASSERT_FATAL (arg.ret == 0);
 | 
			
		||||
 | 
			
		||||
  rc = dds_delete (par);
 | 
			
		||||
  CU_ASSERT_FATAL (rc == 0);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -132,6 +132,7 @@ CU_Test(ddsc_instance_get_key, registered_instance, .init=setup, .fini=teardown)
 | 
			
		|||
    ret = dds_instance_get_key(writer, handle, &key_data);
 | 
			
		||||
 | 
			
		||||
    CU_ASSERT_PTR_NOT_NULL_FATAL(key_data.ip);
 | 
			
		||||
    assert (key_data.ip != NULL); /* for the benefit of clang's static analyzer */
 | 
			
		||||
    CU_ASSERT_STRING_EQUAL_FATAL(key_data.ip, data.ip);
 | 
			
		||||
    CU_ASSERT_EQUAL_FATAL(key_data.port, data.port);
 | 
			
		||||
    CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
 | 
			
		||||
| 
						 | 
				
			
			@ -162,6 +163,7 @@ CU_Test(ddsc_instance_get_key, readcondition, .init=setup, .fini=teardown)
 | 
			
		|||
    ret = dds_instance_get_key(readcondition, handle, &key_data);
 | 
			
		||||
 | 
			
		||||
    CU_ASSERT_PTR_NOT_NULL_FATAL(key_data.ip);
 | 
			
		||||
    assert (key_data.ip != NULL); /* for the benefit of clang's static analyzer */
 | 
			
		||||
    CU_ASSERT_STRING_EQUAL_FATAL(key_data.ip, data.ip);
 | 
			
		||||
    CU_ASSERT_EQUAL_FATAL(key_data.port, data.port);
 | 
			
		||||
    CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
 | 
			
		||||
| 
						 | 
				
			
			@ -192,6 +194,7 @@ CU_Test(ddsc_instance_get_key, querycondition, .init=setup, .fini=teardown)
 | 
			
		|||
    ret = dds_instance_get_key(querycondition, handle, &key_data);
 | 
			
		||||
 | 
			
		||||
    CU_ASSERT_PTR_NOT_NULL_FATAL(key_data.ip);
 | 
			
		||||
    assert (key_data.ip != NULL); /* for the benefit of clang's static analyzer */
 | 
			
		||||
    CU_ASSERT_STRING_EQUAL_FATAL(key_data.ip, data.ip);
 | 
			
		||||
    CU_ASSERT_EQUAL_FATAL(key_data.port, data.port);
 | 
			
		||||
    CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -727,7 +727,9 @@ CU_Test(ddsc_listener, publication_matched, .init=init_triggering_test, .fini=fi
 | 
			
		|||
    CU_ASSERT_EQUAL_FATAL(publication_matched.last_subscription_handle, reader_hdl);
 | 
			
		||||
 | 
			
		||||
    /* Reset the trigger flags. */
 | 
			
		||||
    ddsrt_mutex_lock(&g_mutex);
 | 
			
		||||
    cb_called = 0;
 | 
			
		||||
    ddsrt_mutex_unlock(&g_mutex);
 | 
			
		||||
 | 
			
		||||
    /* Un-match the publication by deleting the reader. */
 | 
			
		||||
    dds_delete(g_reader);
 | 
			
		||||
| 
						 | 
				
			
			@ -789,7 +791,9 @@ CU_Test(ddsc_listener, subscription_matched, .init=init_triggering_test, .fini=f
 | 
			
		|||
    CU_ASSERT_EQUAL_FATAL(subscription_matched.last_publication_handle, writer_hdl);
 | 
			
		||||
 | 
			
		||||
    /* Reset the trigger flags. */
 | 
			
		||||
    ddsrt_mutex_lock(&g_mutex);
 | 
			
		||||
    cb_called = 0;
 | 
			
		||||
    ddsrt_mutex_unlock(&g_mutex);
 | 
			
		||||
 | 
			
		||||
    /* Un-match the subscription by deleting the writer. */
 | 
			
		||||
    dds_delete(g_writer);
 | 
			
		||||
| 
						 | 
				
			
			@ -903,8 +907,10 @@ CU_Test(ddsc_listener, data_available, .init=init_triggering_test, .fini=fini_tr
 | 
			
		|||
 | 
			
		||||
    /* Deleting the writer causes unregisters (or dispose+unregister), and those
 | 
			
		||||
       should trigger DATA_AVAILABLE as well */
 | 
			
		||||
    ddsrt_mutex_lock(&g_mutex);
 | 
			
		||||
    cb_called = 0;
 | 
			
		||||
    cb_reader = 0;
 | 
			
		||||
    ddsrt_mutex_unlock(&g_mutex);
 | 
			
		||||
    ret = dds_delete (g_writer);
 | 
			
		||||
    CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
 | 
			
		||||
    g_writer = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -942,8 +948,10 @@ CU_Test(ddsc_listener, data_available_delete_writer, .init=init_triggering_test,
 | 
			
		|||
    CU_ASSERT_EQUAL_FATAL(cb_reader, g_reader);
 | 
			
		||||
 | 
			
		||||
    /* Deleting the writer must trigger DATA_AVAILABLE as well */
 | 
			
		||||
    ddsrt_mutex_lock(&g_mutex);
 | 
			
		||||
    cb_called = 0;
 | 
			
		||||
    cb_reader = 0;
 | 
			
		||||
    ddsrt_mutex_unlock(&g_mutex);
 | 
			
		||||
    ret = dds_delete (g_writer);
 | 
			
		||||
    CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
 | 
			
		||||
    g_writer = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -991,8 +999,10 @@ CU_Test(ddsc_listener, data_available_delete_writer_disposed, .init=init_trigger
 | 
			
		|||
    } while (ret > 0);
 | 
			
		||||
 | 
			
		||||
    /* Deleting the writer should not trigger DATA_AVAILABLE with all instances empty & disposed */
 | 
			
		||||
    ddsrt_mutex_lock(&g_mutex);
 | 
			
		||||
    cb_called = 0;
 | 
			
		||||
    cb_reader = 0;
 | 
			
		||||
    ddsrt_mutex_unlock(&g_mutex);
 | 
			
		||||
    ret = dds_delete (g_writer);
 | 
			
		||||
    CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
 | 
			
		||||
    g_writer = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -1174,7 +1184,9 @@ CU_Test(ddsc_listener, liveliness_changed, .init=init_triggering_test, .fini=fin
 | 
			
		|||
    CU_ASSERT_EQUAL_FATAL(liveliness_changed.last_publication_handle, writer_hdl);
 | 
			
		||||
 | 
			
		||||
    /* Reset the trigger flags. */
 | 
			
		||||
    ddsrt_mutex_lock(&g_mutex);
 | 
			
		||||
    cb_called = 0;
 | 
			
		||||
    ddsrt_mutex_unlock(&g_mutex);
 | 
			
		||||
 | 
			
		||||
    /* Change liveliness again by deleting the writer. */
 | 
			
		||||
    dds_delete(g_writer);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -47,7 +47,8 @@ CU_Test(ddsc_participant, create_with_no_conf_no_env)
 | 
			
		|||
  dds_domainid_t domain_id;
 | 
			
		||||
  dds_domainid_t valid_domain=3;
 | 
			
		||||
 | 
			
		||||
  ddsrt_unsetenv(DDS_PROJECT_NAME_NOSPACE_CAPS"_URI");
 | 
			
		||||
  status = ddsrt_unsetenv(DDS_PROJECT_NAME_NOSPACE_CAPS"_URI");
 | 
			
		||||
  CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_OK);
 | 
			
		||||
 | 
			
		||||
  //valid specific domain value
 | 
			
		||||
  participant2 = dds_create_participant (valid_domain, NULL, NULL);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -277,7 +277,50 @@ CU_Theory((dds_entity_t *par, dds_entity_t *top), ddsc_reader_create, non_partic
 | 
			
		|||
}
 | 
			
		||||
/*************************************************************************************************/
 | 
			
		||||
 | 
			
		||||
/*************************************************************************************************/
 | 
			
		||||
CU_Test(ddsc_reader_create, wrong_participant, .init=reader_init, .fini=reader_fini)
 | 
			
		||||
{
 | 
			
		||||
    dds_entity_t participant2 = dds_create_participant(DDS_DOMAIN_DEFAULT, NULL, NULL);
 | 
			
		||||
    CU_ASSERT_FATAL(participant2 > 0);
 | 
			
		||||
    dds_entity_t reader = dds_create_reader(participant2, g_topic, NULL, NULL);
 | 
			
		||||
    CU_ASSERT_EQUAL_FATAL(reader, DDS_RETCODE_BAD_PARAMETER);
 | 
			
		||||
    dds_delete(participant2);
 | 
			
		||||
}
 | 
			
		||||
/*************************************************************************************************/
 | 
			
		||||
 | 
			
		||||
/*************************************************************************************************/
 | 
			
		||||
CU_Test(ddsc_reader_create, participant_mismatch)
 | 
			
		||||
{
 | 
			
		||||
    dds_entity_t par1 = 0;
 | 
			
		||||
    dds_entity_t par2 = 0;
 | 
			
		||||
    dds_entity_t sub1 = 0;
 | 
			
		||||
    dds_entity_t top2 = 0;
 | 
			
		||||
    dds_entity_t reader = 0;
 | 
			
		||||
    char name[100];
 | 
			
		||||
 | 
			
		||||
    par1 = dds_create_participant(DDS_DOMAIN_DEFAULT, NULL, NULL);
 | 
			
		||||
    CU_ASSERT_FATAL(par1 > 0);
 | 
			
		||||
    par2 = dds_create_participant(DDS_DOMAIN_DEFAULT, NULL, NULL);
 | 
			
		||||
    CU_ASSERT_FATAL(par2 > 0);
 | 
			
		||||
 | 
			
		||||
    sub1 = dds_create_subscriber(par1, NULL, NULL);
 | 
			
		||||
    CU_ASSERT_FATAL(sub1 > 0);
 | 
			
		||||
 | 
			
		||||
    top2 = dds_create_topic(par2, &Space_Type1_desc, create_topic_name("ddsc_reader_participant_mismatch", name, sizeof name), NULL, NULL);
 | 
			
		||||
    CU_ASSERT_FATAL(top2 > 0);
 | 
			
		||||
 | 
			
		||||
    /* Create reader with participant mismatch. */
 | 
			
		||||
    reader = dds_create_reader(sub1, top2, NULL, NULL);
 | 
			
		||||
 | 
			
		||||
    /* Expect the creation to have failed. */
 | 
			
		||||
    CU_ASSERT_FATAL(reader <= 0);
 | 
			
		||||
 | 
			
		||||
    dds_delete(top2);
 | 
			
		||||
    dds_delete(sub1);
 | 
			
		||||
    dds_delete(par2);
 | 
			
		||||
    dds_delete(par1);
 | 
			
		||||
}
 | 
			
		||||
/*************************************************************************************************/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -256,6 +256,39 @@ CU_Theory((dds_entity_t *par), ddsc_waitset_create, non_participants, .init=ddsc
 | 
			
		|||
}
 | 
			
		||||
/*************************************************************************************************/
 | 
			
		||||
 | 
			
		||||
/*************************************************************************************************/
 | 
			
		||||
CU_Test (ddsc_waitset_create, domain)
 | 
			
		||||
{
 | 
			
		||||
    dds_entity_t par, dom, ws;
 | 
			
		||||
    dds_return_t rc;
 | 
			
		||||
    par = dds_create_participant (0, NULL, NULL);
 | 
			
		||||
    CU_ASSERT_FATAL (par > 0);
 | 
			
		||||
    dom = dds_get_parent (par);
 | 
			
		||||
    CU_ASSERT_FATAL (dom > 0);
 | 
			
		||||
    ws = dds_create_waitset (dom);
 | 
			
		||||
    CU_ASSERT_FATAL (ws > 0);
 | 
			
		||||
    rc = dds_delete (dom);
 | 
			
		||||
    CU_ASSERT_FATAL (rc == 0);
 | 
			
		||||
}
 | 
			
		||||
/*************************************************************************************************/
 | 
			
		||||
 | 
			
		||||
/*************************************************************************************************/
 | 
			
		||||
CU_Test (ddsc_waitset_create, cyclonedds)
 | 
			
		||||
{
 | 
			
		||||
    dds_entity_t ws;
 | 
			
		||||
    dds_return_t rc;
 | 
			
		||||
    /* Expect an uninitialised library */
 | 
			
		||||
    rc = dds_get_parent (DDS_CYCLONEDDS_HANDLE);
 | 
			
		||||
    CU_ASSERT_FATAL (rc == DDS_RETCODE_PRECONDITION_NOT_MET);
 | 
			
		||||
    ws = dds_create_waitset (DDS_CYCLONEDDS_HANDLE);
 | 
			
		||||
    CU_ASSERT_FATAL (ws > 0);
 | 
			
		||||
    rc = dds_delete (DDS_CYCLONEDDS_HANDLE);
 | 
			
		||||
    CU_ASSERT_FATAL (rc == 0);
 | 
			
		||||
    /* And the same afterward */
 | 
			
		||||
    rc = dds_get_parent (DDS_CYCLONEDDS_HANDLE);
 | 
			
		||||
    CU_ASSERT_FATAL (rc == DDS_RETCODE_PRECONDITION_NOT_MET);
 | 
			
		||||
}
 | 
			
		||||
/*************************************************************************************************/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**************************************************************************************************
 | 
			
		||||
| 
						 | 
				
			
			@ -318,6 +351,52 @@ CU_Test(ddsc_waitset_attach, deleted_waitset, .init=ddsc_waitset_basic_init, .fi
 | 
			
		|||
}
 | 
			
		||||
/*************************************************************************************************/
 | 
			
		||||
 | 
			
		||||
/*************************************************************************************************/
 | 
			
		||||
CU_TheoryDataPoints(ddsc_waitset_attach, scoping) = {
 | 
			
		||||
    CU_DataPoints (int, -9, -1, -2,  0,  0,  2), /* owner: -9: lib, -1: dom0, -2: dom1 */
 | 
			
		||||
    CU_DataPoints (int,  0,  0,  2,  0,  0,  2), /* ok1: participant one can attach */
 | 
			
		||||
    CU_DataPoints (int,  3,  1,  3, -1, -1, -1), /* ok2: other participant one can attach, or -1 */
 | 
			
		||||
    CU_DataPoints (int, -1,  2,  0,  1,  2,  0), /* fail: participant that one cannot attach, or -1 */
 | 
			
		||||
};
 | 
			
		||||
CU_Theory ((int owner, int ok1, int ok2, int fail), ddsc_waitset_attach, scoping)
 | 
			
		||||
{
 | 
			
		||||
    dds_entity_t par[4], dom[2], ws, ownh;
 | 
			
		||||
    dds_return_t rc;
 | 
			
		||||
    for (int i = 0; i < 2; i++) {
 | 
			
		||||
        for (int j = 0; j < 2; j++) {
 | 
			
		||||
            par[2*i+j] = dds_create_participant ((dds_domainid_t) i, NULL, NULL);
 | 
			
		||||
            CU_ASSERT_FATAL (par[2*i+j] > 0);
 | 
			
		||||
        }
 | 
			
		||||
        dom[i] = dds_get_parent (par[2*i]);
 | 
			
		||||
        CU_ASSERT_FATAL (dom[i] > 0);
 | 
			
		||||
    }
 | 
			
		||||
    if (owner == -9) {
 | 
			
		||||
        ownh = DDS_CYCLONEDDS_HANDLE;
 | 
			
		||||
    } else if (owner < 0) {
 | 
			
		||||
        ownh = dom[-owner - 1];
 | 
			
		||||
    } else {
 | 
			
		||||
        ownh = par[owner];
 | 
			
		||||
    }
 | 
			
		||||
    printf ("%d %d %d %d | %"PRId32"\n", owner, ok1, ok2, fail, ownh);
 | 
			
		||||
    ws = dds_create_waitset (ownh);
 | 
			
		||||
    CU_ASSERT_FATAL (ws > 0);
 | 
			
		||||
    rc = dds_waitset_attach (ws, par[ok1], 0);
 | 
			
		||||
    CU_ASSERT_FATAL (rc == 0);
 | 
			
		||||
    if (ok2 >= 0) {
 | 
			
		||||
        rc = dds_waitset_attach (ws, par[ok2], 1);
 | 
			
		||||
        CU_ASSERT_FATAL (rc == 0);
 | 
			
		||||
    }
 | 
			
		||||
    if (fail >= 0) {
 | 
			
		||||
        rc = dds_waitset_attach (ws, par[fail], 2);
 | 
			
		||||
        CU_ASSERT_FATAL (rc == DDS_RETCODE_BAD_PARAMETER);
 | 
			
		||||
    }
 | 
			
		||||
    rc = dds_delete (DDS_CYCLONEDDS_HANDLE);
 | 
			
		||||
    CU_ASSERT_FATAL (rc == 0);
 | 
			
		||||
    rc = dds_get_parent (DDS_CYCLONEDDS_HANDLE);
 | 
			
		||||
    CU_ASSERT_FATAL (rc == DDS_RETCODE_PRECONDITION_NOT_MET);
 | 
			
		||||
}
 | 
			
		||||
/*************************************************************************************************/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**************************************************************************************************
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										398
									
								
								src/core/ddsc/tests/waitset_torture.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										398
									
								
								src/core/ddsc/tests/waitset_torture.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,398 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright(c) 2019 ADLINK Technology Limited and others
 | 
			
		||||
 *
 | 
			
		||||
 * This program and the accompanying materials are made available under the
 | 
			
		||||
 * terms of the Eclipse Public License v. 2.0 which is available at
 | 
			
		||||
 * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
 | 
			
		||||
 * v. 1.0 which is available at
 | 
			
		||||
 * http://www.eclipse.org/org/documents/edl-v10.php.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
 | 
			
		||||
#include "dds/dds.h"
 | 
			
		||||
#include "CUnit/Theory.h"
 | 
			
		||||
#include "RoundTrip.h"
 | 
			
		||||
 | 
			
		||||
#include "dds/ddsrt/cdtors.h"
 | 
			
		||||
#include "dds/ddsrt/misc.h"
 | 
			
		||||
#include "dds/ddsrt/process.h"
 | 
			
		||||
#include "dds/ddsrt/threads.h"
 | 
			
		||||
#include "dds/ddsrt/atomics.h"
 | 
			
		||||
#include "dds/ddsrt/time.h"
 | 
			
		||||
#include "dds/ddsrt/random.h"
 | 
			
		||||
 | 
			
		||||
#define N_WAITSETS 20
 | 
			
		||||
#define N_ENTITIES 32
 | 
			
		||||
 | 
			
		||||
#define N_GUARDCONDS 20
 | 
			
		||||
#define N_SUBSCRIBERS 4
 | 
			
		||||
#define N_READERS 4
 | 
			
		||||
#define N_READCONDS 4
 | 
			
		||||
 | 
			
		||||
static dds_entity_t ppant;
 | 
			
		||||
static dds_entity_t topic;
 | 
			
		||||
 | 
			
		||||
static ddsrt_atomic_uint32_t terminate;
 | 
			
		||||
static ddsrt_atomic_uint32_t waitsets[N_WAITSETS];
 | 
			
		||||
static ddsrt_atomic_uint32_t entities[N_ENTITIES], signalled;
 | 
			
		||||
 | 
			
		||||
static ddsrt_atomic_uint32_t attach_ok, detach_ok, settrig_ok;
 | 
			
		||||
static ddsrt_atomic_uint32_t create_ent_ok[5], delete_ent_ok[5];
 | 
			
		||||
static ddsrt_atomic_uint32_t create_ws_ok, delete_ws_ok;
 | 
			
		||||
 | 
			
		||||
#define RESERVED      ((uint32_t) 0xffffffffu)
 | 
			
		||||
 | 
			
		||||
static void init_prng (ddsrt_prng_t *prng)
 | 
			
		||||
{
 | 
			
		||||
  ddsrt_prng_seed_t prng_seed;
 | 
			
		||||
  for (size_t i = 0; i < sizeof (prng_seed.key) / sizeof (prng_seed.key[0]); i++)
 | 
			
		||||
    prng_seed.key[i] = ddsrt_random ();
 | 
			
		||||
  ddsrt_prng_init (prng, &prng_seed);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void choose_index (uint32_t *p_idx, uint32_t *p_handle, ddsrt_prng_t *prng, ddsrt_atomic_uint32_t elems[], size_t nelems)
 | 
			
		||||
{
 | 
			
		||||
  uint32_t idx, h, h1;
 | 
			
		||||
retry_idx:
 | 
			
		||||
  idx = ddsrt_prng_random (prng) % (uint32_t) nelems;
 | 
			
		||||
retry_cas:
 | 
			
		||||
  h = ddsrt_atomic_ld32 (&elems[idx]);
 | 
			
		||||
  if (h == 0)
 | 
			
		||||
    h1 = RESERVED;
 | 
			
		||||
  else if ((int32_t) h > 0)
 | 
			
		||||
    h1 = 0;
 | 
			
		||||
  else
 | 
			
		||||
    goto retry_idx;
 | 
			
		||||
  if (!ddsrt_atomic_cas32 (&elems[idx], h, h1))
 | 
			
		||||
    goto retry_cas;
 | 
			
		||||
  *p_idx = idx;
 | 
			
		||||
  *p_handle = h;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static dds_entity_t pick_a_subscriber (void)
 | 
			
		||||
{
 | 
			
		||||
  uint32_t idx = ddsrt_random () % N_SUBSCRIBERS;
 | 
			
		||||
  uint32_t x = ddsrt_atomic_ld32 (&entities[N_GUARDCONDS + idx]);
 | 
			
		||||
  return (dds_entity_t) x;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static dds_entity_t pick_a_reader (void)
 | 
			
		||||
{
 | 
			
		||||
  uint32_t idx = ddsrt_random () % N_READERS;
 | 
			
		||||
  uint32_t x = ddsrt_atomic_ld32 (&entities[N_GUARDCONDS + N_SUBSCRIBERS + idx]);
 | 
			
		||||
  return (dds_entity_t) x;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int index_to_counter_index (uint32_t idx)
 | 
			
		||||
{
 | 
			
		||||
  if (idx < N_GUARDCONDS)
 | 
			
		||||
    return 0;
 | 
			
		||||
  else if (idx < N_GUARDCONDS + N_SUBSCRIBERS)
 | 
			
		||||
    return 1;
 | 
			
		||||
  else if (idx < N_GUARDCONDS + N_SUBSCRIBERS + N_READERS)
 | 
			
		||||
    return 2;
 | 
			
		||||
  else
 | 
			
		||||
    return 4;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static uint32_t guardcond_create_delete_thread (void *varg)
 | 
			
		||||
{
 | 
			
		||||
  (void) varg;
 | 
			
		||||
  ddsrt_prng_t prng;
 | 
			
		||||
  init_prng (&prng);
 | 
			
		||||
  while (!ddsrt_atomic_ld32 (&terminate))
 | 
			
		||||
  {
 | 
			
		||||
    uint32_t idx, handle;
 | 
			
		||||
    choose_index (&idx, &handle, &prng, entities, N_ENTITIES);
 | 
			
		||||
    if (handle == 0)
 | 
			
		||||
    {
 | 
			
		||||
      dds_entity_t ent = 0, parent = 0;
 | 
			
		||||
 | 
			
		||||
      if (idx < N_GUARDCONDS)
 | 
			
		||||
        ent = dds_create_guardcondition (DDS_CYCLONEDDS_HANDLE);
 | 
			
		||||
      else if (idx < N_GUARDCONDS + N_SUBSCRIBERS)
 | 
			
		||||
        ent = dds_create_subscriber (ppant, NULL, NULL);
 | 
			
		||||
      else if (idx < N_GUARDCONDS + N_SUBSCRIBERS + N_READERS)
 | 
			
		||||
      {
 | 
			
		||||
        if ((parent = pick_a_subscriber ()) == 0)
 | 
			
		||||
          parent = ppant;
 | 
			
		||||
        ent = dds_create_reader (parent, topic, NULL, NULL);
 | 
			
		||||
      }
 | 
			
		||||
      else if ((parent = pick_a_reader ()) != 0)
 | 
			
		||||
      {
 | 
			
		||||
        ent = dds_create_readcondition (parent, DDS_ANY_STATE);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (ent > 0)
 | 
			
		||||
      {
 | 
			
		||||
        ddsrt_atomic_inc32 (&create_ent_ok[index_to_counter_index (idx) + (parent == ppant)]);
 | 
			
		||||
        ddsrt_atomic_st32 (&entities[idx], (uint32_t) ent);
 | 
			
		||||
      }
 | 
			
		||||
      else if (ent < 0 && idx < N_GUARDCONDS)
 | 
			
		||||
      {
 | 
			
		||||
        fprintf (stderr, "dds_create_guardcondition failed: %s\n", dds_strretcode (ent));
 | 
			
		||||
        ddsrt_atomic_st32 (&terminate, 1);
 | 
			
		||||
        return 1;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
      dds_return_t rc = dds_delete ((dds_entity_t) handle);
 | 
			
		||||
      if (rc == 0)
 | 
			
		||||
        ddsrt_atomic_inc32 (&delete_ent_ok[index_to_counter_index (idx)]);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static uint32_t waitset_create_delete_thread (void *varg)
 | 
			
		||||
{
 | 
			
		||||
  (void) varg;
 | 
			
		||||
  ddsrt_prng_t prng;
 | 
			
		||||
  init_prng (&prng);
 | 
			
		||||
  while (!ddsrt_atomic_ld32 (&terminate))
 | 
			
		||||
  {
 | 
			
		||||
    uint32_t idx, handle;
 | 
			
		||||
    choose_index (&idx, &handle, &prng, waitsets, N_WAITSETS);
 | 
			
		||||
    if (handle == 0)
 | 
			
		||||
    {
 | 
			
		||||
      dds_entity_t ws = dds_create_waitset (DDS_CYCLONEDDS_HANDLE);
 | 
			
		||||
      if (ws < 0)
 | 
			
		||||
      {
 | 
			
		||||
        fprintf (stderr, "dds_create_waitset failed: %s\n", dds_strretcode (ws));
 | 
			
		||||
        ddsrt_atomic_st32 (&terminate, 1);
 | 
			
		||||
        return 1;
 | 
			
		||||
      }
 | 
			
		||||
      ddsrt_atomic_inc32 (&create_ws_ok);
 | 
			
		||||
      ddsrt_atomic_st32 (&waitsets[idx], (uint32_t) ws);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
      dds_return_t rc = dds_delete ((dds_entity_t) handle);
 | 
			
		||||
      if (rc == 0)
 | 
			
		||||
        ddsrt_atomic_inc32 (&delete_ws_ok);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static uint32_t guardcond_trigger_thread (void *varg)
 | 
			
		||||
{
 | 
			
		||||
  (void) varg;
 | 
			
		||||
  ddsrt_prng_t prng;
 | 
			
		||||
  init_prng (&prng);
 | 
			
		||||
  while (!ddsrt_atomic_ld32 (&terminate))
 | 
			
		||||
  {
 | 
			
		||||
    uint32_t idx = ddsrt_prng_random (&prng) % N_ENTITIES;
 | 
			
		||||
    uint32_t h = ddsrt_atomic_ld32 (&entities[idx]);
 | 
			
		||||
    if ((int32_t) h <= 0)
 | 
			
		||||
      continue;
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
      uint32_t s, s1;
 | 
			
		||||
      do {
 | 
			
		||||
        s = ddsrt_atomic_ld32 (&signalled);
 | 
			
		||||
        s1 = s ^ (1u << idx);
 | 
			
		||||
      } while (!ddsrt_atomic_cas32 (&signalled, s, s1));
 | 
			
		||||
      dds_return_t rc = dds_set_guardcondition ((dds_entity_t) h, (s & (1u << idx)) ? false : true);
 | 
			
		||||
      if (rc == 0)
 | 
			
		||||
        ddsrt_atomic_inc32 (&settrig_ok);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static uint32_t waitset_attach_detach_thread (void *varg)
 | 
			
		||||
{
 | 
			
		||||
  (void) varg;
 | 
			
		||||
  ddsrt_prng_t prng;
 | 
			
		||||
  init_prng (&prng);
 | 
			
		||||
  while (!ddsrt_atomic_ld32 (&terminate))
 | 
			
		||||
  {
 | 
			
		||||
    uint32_t wsidx = ddsrt_prng_random (&prng) % N_WAITSETS;
 | 
			
		||||
    uint32_t wsh = ddsrt_atomic_ld32 (&waitsets[wsidx]);
 | 
			
		||||
    if ((int32_t) wsh <= 0)
 | 
			
		||||
      continue;
 | 
			
		||||
 | 
			
		||||
    uint32_t gcidx = ddsrt_prng_random (&prng) % N_ENTITIES;
 | 
			
		||||
    uint32_t gch = ddsrt_atomic_ld32 (&entities[gcidx]);
 | 
			
		||||
    if ((int32_t) gch <= 0)
 | 
			
		||||
      continue;
 | 
			
		||||
 | 
			
		||||
    dds_return_t rc;
 | 
			
		||||
    rc = dds_waitset_detach ((dds_entity_t) wsh, (dds_entity_t) gch);
 | 
			
		||||
    if (rc == 0)
 | 
			
		||||
    {
 | 
			
		||||
      ddsrt_atomic_inc32 (&detach_ok);
 | 
			
		||||
    }
 | 
			
		||||
    else if (rc != DDS_RETCODE_PRECONDITION_NOT_MET && rc != DDS_RETCODE_BAD_PARAMETER)
 | 
			
		||||
    {
 | 
			
		||||
      /* attempts at attaching a guard condition twice or detaching an unattached
 | 
			
		||||
         one are expected, and those result in a PRECONDITION_NOT_MET */
 | 
			
		||||
      fprintf (stderr, "dds_waitset_detach 0x%"PRIx32" 0x%"PRIx32" failed: %s\n", (dds_entity_t) wsh, (dds_entity_t) gch, dds_strretcode (rc));
 | 
			
		||||
      ddsrt_atomic_st32 (&terminate, 1);
 | 
			
		||||
      return 1;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
      /* should imply it is already attached, so try detaching */
 | 
			
		||||
      rc = dds_waitset_attach ((dds_entity_t) wsh, (dds_entity_t) gch, 0);
 | 
			
		||||
      if (rc == 0)
 | 
			
		||||
      {
 | 
			
		||||
        ddsrt_atomic_inc32 (&attach_ok);
 | 
			
		||||
      }
 | 
			
		||||
      else if (rc != DDS_RETCODE_PRECONDITION_NOT_MET && rc != DDS_RETCODE_BAD_PARAMETER)
 | 
			
		||||
      {
 | 
			
		||||
        fprintf (stderr, "dds_waitset_attach 0x%"PRIx32" 0x%"PRIx32" failed: %s\n", (dds_entity_t) wsh, (dds_entity_t) gch, dds_strretcode (rc));
 | 
			
		||||
        ddsrt_atomic_st32 (&terminate, 1);
 | 
			
		||||
        return 1;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
CU_Test (ddsc_waitset, torture)
 | 
			
		||||
{
 | 
			
		||||
  dds_return_t rc;
 | 
			
		||||
  ddsrt_thread_t tids[8];
 | 
			
		||||
  ddsrt_threadattr_t tattr;
 | 
			
		||||
  ddsrt_threadattr_init (&tattr);
 | 
			
		||||
 | 
			
		||||
  /* This keeps the library initialised -- it shouldn't be necessary */
 | 
			
		||||
  ppant = dds_create_participant (DDS_DOMAIN_DEFAULT, NULL, NULL);
 | 
			
		||||
  CU_ASSERT_FATAL (ppant > 0);
 | 
			
		||||
  topic = dds_create_topic (ppant, &RoundTripModule_DataType_desc, "waitset_torture_topic", NULL, NULL);
 | 
			
		||||
  CU_ASSERT_FATAL (topic > 0);
 | 
			
		||||
 | 
			
		||||
  rc = ddsrt_thread_create (&tids[0], "gc_cd", &tattr, guardcond_create_delete_thread, 0);
 | 
			
		||||
  CU_ASSERT_FATAL (rc == 0);
 | 
			
		||||
  rc = ddsrt_thread_create (&tids[1], "gc_cd", &tattr, guardcond_create_delete_thread, 0);
 | 
			
		||||
  CU_ASSERT_FATAL (rc == 0);
 | 
			
		||||
  rc = ddsrt_thread_create (&tids[2], "ws_cd", &tattr, waitset_create_delete_thread, 0);
 | 
			
		||||
  CU_ASSERT_FATAL (rc == 0);
 | 
			
		||||
  rc = ddsrt_thread_create (&tids[3], "ws_cd", &tattr, waitset_create_delete_thread, 0);
 | 
			
		||||
  CU_ASSERT_FATAL (rc == 0);
 | 
			
		||||
  rc = ddsrt_thread_create (&tids[4], "gc_t", &tattr, guardcond_trigger_thread, 0);
 | 
			
		||||
  CU_ASSERT_FATAL (rc == 0);
 | 
			
		||||
  rc = ddsrt_thread_create (&tids[5], "gc_t", &tattr, guardcond_trigger_thread, 0);
 | 
			
		||||
  CU_ASSERT_FATAL (rc == 0);
 | 
			
		||||
  rc = ddsrt_thread_create (&tids[6], "ws_ad", &tattr, waitset_attach_detach_thread, 0);
 | 
			
		||||
  CU_ASSERT_FATAL (rc == 0);
 | 
			
		||||
  rc = ddsrt_thread_create (&tids[7], "ws_ad", &tattr, waitset_attach_detach_thread, 0);
 | 
			
		||||
  CU_ASSERT_FATAL (rc == 0);
 | 
			
		||||
 | 
			
		||||
  uint32_t wait_err = 0, wait_ok[N_ENTITIES + 1] = { 0 };
 | 
			
		||||
  dds_time_t tstop = dds_time () + DDS_SECS (5);
 | 
			
		||||
  while (dds_time () < tstop && !ddsrt_atomic_ld32 (&terminate))
 | 
			
		||||
  {
 | 
			
		||||
    /* Try waiting on the waitset in slot 0 if it exists (it shouldn't make much
 | 
			
		||||
       difference which waitset we use; this is easy).  There are never more than
 | 
			
		||||
       N_ENTITIES guard conditions, so there are also never more than that many
 | 
			
		||||
       triggering entities, and so we can easily do a small histogram.  (The longer
 | 
			
		||||
       you run it, the longer the tail of triggering entities one expects.)
 | 
			
		||||
 | 
			
		||||
       Error handling: the waitset may be deleted in between loading the handle
 | 
			
		||||
       and pinning it wait(), so BAD_PARAMETER is to be expected.  If the "extragc"
 | 
			
		||||
       isn't there to ensure the library stays initialised, it is even possible
 | 
			
		||||
       that we get PRECONDITION_NOT_MET if it just so happened that with the
 | 
			
		||||
       deleting of that waitset, no entities remain at all. */
 | 
			
		||||
    dds_entity_t ws = (dds_entity_t) ddsrt_atomic_ld32 (&waitsets[0]);
 | 
			
		||||
    if (ws > 0)
 | 
			
		||||
    {
 | 
			
		||||
      int32_t n = dds_waitset_wait (ws, NULL, 0, DDS_MSECS (10));
 | 
			
		||||
      if (!((rc >= 0 && rc <= N_ENTITIES) || rc == DDS_RETCODE_BAD_PARAMETER))
 | 
			
		||||
      {
 | 
			
		||||
        fprintf (stderr, "dds_waitset_wait failed: %s\n", dds_strretcode (rc));
 | 
			
		||||
        ddsrt_atomic_st32 (&terminate, 1);
 | 
			
		||||
        rc = DDS_RETCODE_ERROR;
 | 
			
		||||
      }
 | 
			
		||||
      else
 | 
			
		||||
      {
 | 
			
		||||
        if (n >= 0)
 | 
			
		||||
          wait_ok[n]++;
 | 
			
		||||
        else
 | 
			
		||||
          wait_err++;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  ddsrt_atomic_st32 (&terminate, 1);
 | 
			
		||||
  CU_ASSERT (rc != DDS_RETCODE_ERROR);
 | 
			
		||||
 | 
			
		||||
  for (size_t i = 0; i < sizeof (tids) / sizeof (tids[0]); i++)
 | 
			
		||||
  {
 | 
			
		||||
    uint32_t retval;
 | 
			
		||||
    rc = ddsrt_thread_join (tids[i], &retval);
 | 
			
		||||
    CU_ASSERT_FATAL (rc == 0);
 | 
			
		||||
    CU_ASSERT (retval == 0);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /* The threads don't bother to clean up, so delete whatever guard conditions and
 | 
			
		||||
     waitsets happen to still exist.  Passing garbage into dds_delete is supposed
 | 
			
		||||
     to work, so don't bother with any validation or error checking. */
 | 
			
		||||
  for (uint32_t i = 0; i < N_ENTITIES; i++)
 | 
			
		||||
  {
 | 
			
		||||
    if (dds_delete ((dds_entity_t)  ddsrt_atomic_ld32 (&entities[i])) == DDS_RETCODE_OK)
 | 
			
		||||
      ddsrt_atomic_inc32 (&delete_ent_ok[index_to_counter_index (i)]);
 | 
			
		||||
  }
 | 
			
		||||
  for (uint32_t i = 0; i < N_WAITSETS; i++)
 | 
			
		||||
  {
 | 
			
		||||
    if (dds_delete ((dds_entity_t) ddsrt_atomic_ld32 (&waitsets[i])) == DDS_RETCODE_OK)
 | 
			
		||||
      ddsrt_atomic_inc32 (&delete_ws_ok);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /* All we should be left within the participant is the topic */
 | 
			
		||||
  rc = dds_delete (topic);
 | 
			
		||||
  CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
 | 
			
		||||
  rc = dds_get_children (ppant, NULL, 0);
 | 
			
		||||
  CU_ASSERT_FATAL (rc == 0);
 | 
			
		||||
  rc = dds_delete (ppant);
 | 
			
		||||
  CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
 | 
			
		||||
 | 
			
		||||
  printf ("attach %"PRIu32" detach %"PRIu32" settrig %"PRIu32"\n", ddsrt_atomic_ld32 (&attach_ok), ddsrt_atomic_ld32 (&detach_ok), ddsrt_atomic_ld32 (&settrig_ok));
 | 
			
		||||
  printf ("create/delete ent");
 | 
			
		||||
  uint32_t create_ent_ok_sum = 0;
 | 
			
		||||
  for (size_t i = 0; i < sizeof (create_ent_ok) / sizeof (create_ent_ok[0]); i++)
 | 
			
		||||
  {
 | 
			
		||||
    uint32_t c = ddsrt_atomic_ld32 (&create_ent_ok[i]);
 | 
			
		||||
    create_ent_ok_sum += c;
 | 
			
		||||
    printf (" %"PRIu32"/%"PRIu32, c, ddsrt_atomic_ld32 (&delete_ent_ok[i]));
 | 
			
		||||
  }
 | 
			
		||||
  printf ("\n");
 | 
			
		||||
 | 
			
		||||
  {
 | 
			
		||||
    uint32_t rd_cr_sub = ddsrt_atomic_ld32 (&create_ent_ok[2]);
 | 
			
		||||
    uint32_t rd_cr_ppant = ddsrt_atomic_ld32 (&create_ent_ok[3]);
 | 
			
		||||
    uint32_t rd_del = ddsrt_atomic_ld32 (&delete_ent_ok[2]);
 | 
			
		||||
    uint32_t sub_del = ddsrt_atomic_ld32 (&delete_ent_ok[1]);
 | 
			
		||||
    CU_ASSERT (rd_del <= rd_cr_sub + rd_cr_ppant); /* can't have deleted more readers than were created */
 | 
			
		||||
    CU_ASSERT (rd_del >= rd_cr_ppant); /* readers created with ppant as owner must have been deleted explicitly */
 | 
			
		||||
    CU_ASSERT (rd_del - rd_cr_ppant <= sub_del); /* other readers may have been deleted by deleting a sub */
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  printf ("create/delete ws %"PRIu32"/%"PRIu32"\n", ddsrt_atomic_ld32 (&create_ws_ok), ddsrt_atomic_ld32 (&delete_ws_ok));
 | 
			
		||||
  printf ("wait {err %"PRIu32"}", wait_err);
 | 
			
		||||
  uint32_t wait_ok_sum = 0;
 | 
			
		||||
  for (size_t i = 0; i < sizeof (wait_ok) / sizeof (wait_ok[0]); i++)
 | 
			
		||||
  {
 | 
			
		||||
    wait_ok_sum += wait_ok[i];
 | 
			
		||||
    printf (" %"PRIu32, wait_ok[i]);
 | 
			
		||||
  }
 | 
			
		||||
  printf ("\n");
 | 
			
		||||
 | 
			
		||||
  /* Running on Windows on the CI infrastructure has very little concurrency, but Linux
 | 
			
		||||
     and macOS seem ok.  The thresholds here appear to be sufficiently low to not give
 | 
			
		||||
     many spurious failures, while still being sanity check that at least something
 | 
			
		||||
     happened. */
 | 
			
		||||
  CU_ASSERT (ddsrt_atomic_ld32 (&attach_ok) +
 | 
			
		||||
             ddsrt_atomic_ld32 (&settrig_ok) +
 | 
			
		||||
             ddsrt_atomic_ld32 (&create_ws_ok) +
 | 
			
		||||
             create_ent_ok_sum +
 | 
			
		||||
             wait_ok_sum > 1000);
 | 
			
		||||
 | 
			
		||||
  rc = dds_get_parent (DDS_CYCLONEDDS_HANDLE);
 | 
			
		||||
  CU_ASSERT_FATAL (rc == DDS_RETCODE_PRECONDITION_NOT_MET);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -72,6 +72,15 @@ CU_Test(ddsc_create_writer, participant, .init = setup, .fini = teardown)
 | 
			
		|||
    CU_ASSERT_FATAL(writer > 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
CU_Test(ddsc_create_writer, wrong_participant, .init = setup, .fini = teardown)
 | 
			
		||||
{
 | 
			
		||||
    dds_entity_t participant2 = dds_create_participant(DDS_DOMAIN_DEFAULT, NULL, NULL);
 | 
			
		||||
    CU_ASSERT_FATAL(participant2 > 0);
 | 
			
		||||
    writer = dds_create_writer(participant2, topic, NULL, NULL);
 | 
			
		||||
    CU_ASSERT_EQUAL_FATAL(writer, DDS_RETCODE_BAD_PARAMETER);
 | 
			
		||||
    dds_delete(participant2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
CU_Test(ddsc_create_writer, publisher, .init = setup, .fini = teardown)
 | 
			
		||||
{
 | 
			
		||||
    writer = dds_create_writer(publisher, topic, NULL, NULL);
 | 
			
		||||
| 
						 | 
				
			
			@ -107,3 +116,27 @@ CU_Test(ddsc_create_writer, deleted_topic, .init = setup, .fini = teardown)
 | 
			
		|||
    writer = dds_create_writer(publisher, topic, NULL, NULL);
 | 
			
		||||
    CU_ASSERT_EQUAL_FATAL(writer, DDS_RETCODE_BAD_PARAMETER);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
CU_Test(ddsc_create_writer, participant_mismatch, .init = setup, .fini = teardown)
 | 
			
		||||
{
 | 
			
		||||
    dds_entity_t l_par = 0;
 | 
			
		||||
    dds_entity_t l_pub = 0;
 | 
			
		||||
 | 
			
		||||
    /* The call to setup() created the global topic. */
 | 
			
		||||
 | 
			
		||||
    /* Create publisher on local participant. */
 | 
			
		||||
    l_par = dds_create_participant(DDS_DOMAIN_DEFAULT, NULL, NULL);
 | 
			
		||||
    CU_ASSERT_FATAL(l_par > 0);
 | 
			
		||||
    l_pub = dds_create_publisher(l_par, NULL, NULL);
 | 
			
		||||
    CU_ASSERT_FATAL(l_pub > 0);
 | 
			
		||||
 | 
			
		||||
    /* Create writer with local publisher and global topic. */
 | 
			
		||||
    writer = dds_create_writer(l_pub, topic, NULL, NULL);
 | 
			
		||||
 | 
			
		||||
    /* Expect the creation to have failed. */
 | 
			
		||||
    CU_ASSERT_FATAL(writer <= 0);
 | 
			
		||||
 | 
			
		||||
    dds_delete(l_pub);
 | 
			
		||||
    dds_delete(l_par);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,6 +26,7 @@ PREPEND(srcs_ddsi "${CMAKE_CURRENT_LIST_DIR}/src"
 | 
			
		|||
    ddsi_tkmap.c
 | 
			
		||||
    ddsi_vendor.c
 | 
			
		||||
    ddsi_threadmon.c
 | 
			
		||||
    ddsi_rhc.c
 | 
			
		||||
    q_addrset.c
 | 
			
		||||
    q_bitset_inlines.c
 | 
			
		||||
    q_bswap.c
 | 
			
		||||
| 
						 | 
				
			
			@ -53,7 +54,6 @@ PREPEND(srcs_ddsi "${CMAKE_CURRENT_LIST_DIR}/src"
 | 
			
		|||
    q_transmit.c
 | 
			
		||||
    q_inverse_uint32_set.c
 | 
			
		||||
    q_whc.c
 | 
			
		||||
    q_rhc.c
 | 
			
		||||
    q_xevent.c
 | 
			
		||||
    q_xmsg.c
 | 
			
		||||
    q_freelist.c
 | 
			
		||||
| 
						 | 
				
			
			@ -70,6 +70,7 @@ PREPEND(hdrs_private_ddsi "${CMAKE_CURRENT_LIST_DIR}/include/dds/ddsi"
 | 
			
		|||
    ddsi_raweth.h
 | 
			
		||||
    ddsi_ipaddr.h
 | 
			
		||||
    ddsi_mcgroup.h
 | 
			
		||||
    ddsi_plist_generic.h
 | 
			
		||||
    ddsi_serdata.h
 | 
			
		||||
    ddsi_sertopic.h
 | 
			
		||||
    ddsi_serdata_default.h
 | 
			
		||||
| 
						 | 
				
			
			@ -78,6 +79,8 @@ PREPEND(hdrs_private_ddsi "${CMAKE_CURRENT_LIST_DIR}/include/dds/ddsi"
 | 
			
		|||
    ddsi_vendor.h
 | 
			
		||||
    ddsi_threadmon.h
 | 
			
		||||
    ddsi_builtin_topic_if.h
 | 
			
		||||
    ddsi_rhc.h
 | 
			
		||||
    ddsi_guid.h
 | 
			
		||||
    q_addrset.h
 | 
			
		||||
    q_bitset.h
 | 
			
		||||
    q_bswap.h
 | 
			
		||||
| 
						 | 
				
			
			@ -102,7 +105,6 @@ PREPEND(hdrs_private_ddsi "${CMAKE_CURRENT_LIST_DIR}/include/dds/ddsi"
 | 
			
		|||
    q_qosmatch.h
 | 
			
		||||
    q_radmin.h
 | 
			
		||||
    q_receive.h
 | 
			
		||||
    q_rhc.h
 | 
			
		||||
    q_rtps.h
 | 
			
		||||
    q_security.h
 | 
			
		||||
    q_sockwaitset.h
 | 
			
		||||
| 
						 | 
				
			
			@ -128,3 +130,8 @@ install(
 | 
			
		|||
  DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/include/dds"
 | 
			
		||||
  DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
 | 
			
		||||
  COMPONENT dev)
 | 
			
		||||
 | 
			
		||||
# TODO: improve test inclusion.
 | 
			
		||||
if((BUILD_TESTING) AND ((NOT DEFINED MSVC_VERSION) OR (MSVC_VERSION GREATER "1800")))
 | 
			
		||||
  add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/tests")
 | 
			
		||||
endif()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,24 +22,24 @@ extern "C" {
 | 
			
		|||
struct entity_common;
 | 
			
		||||
struct ddsi_tkmap_instance;
 | 
			
		||||
struct ddsi_sertopic;
 | 
			
		||||
struct nn_guid;
 | 
			
		||||
struct ddsi_guid;
 | 
			
		||||
 | 
			
		||||
struct ddsi_builtin_topic_interface {
 | 
			
		||||
  void *arg;
 | 
			
		||||
 | 
			
		||||
  bool (*builtintopic_is_builtintopic) (const struct ddsi_sertopic *topic, void *arg);
 | 
			
		||||
  bool (*builtintopic_is_visible) (const struct nn_guid *guid, nn_vendorid_t vendorid, void *arg);
 | 
			
		||||
  struct ddsi_tkmap_instance * (*builtintopic_get_tkmap_entry) (const struct nn_guid *guid, void *arg);
 | 
			
		||||
  bool (*builtintopic_is_visible) (const struct ddsi_guid *guid, nn_vendorid_t vendorid, void *arg);
 | 
			
		||||
  struct ddsi_tkmap_instance * (*builtintopic_get_tkmap_entry) (const struct ddsi_guid *guid, void *arg);
 | 
			
		||||
  void (*builtintopic_write) (const struct entity_common *e, nn_wctime_t timestamp, bool alive, void *arg);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
inline bool builtintopic_is_visible (const struct ddsi_builtin_topic_interface *btif, const struct nn_guid *guid, nn_vendorid_t vendorid) {
 | 
			
		||||
inline bool builtintopic_is_visible (const struct ddsi_builtin_topic_interface *btif, const struct ddsi_guid *guid, nn_vendorid_t vendorid) {
 | 
			
		||||
  return btif ? btif->builtintopic_is_visible (guid, vendorid, btif->arg) : false;
 | 
			
		||||
}
 | 
			
		||||
inline bool builtintopic_is_builtintopic (const struct ddsi_builtin_topic_interface *btif, const struct ddsi_sertopic *topic) {
 | 
			
		||||
  return btif ? btif->builtintopic_is_builtintopic (topic, btif->arg) : false;
 | 
			
		||||
}
 | 
			
		||||
inline struct ddsi_tkmap_instance *builtintopic_get_tkmap_entry (const struct ddsi_builtin_topic_interface *btif, const struct nn_guid *guid) {
 | 
			
		||||
inline struct ddsi_tkmap_instance *builtintopic_get_tkmap_entry (const struct ddsi_builtin_topic_interface *btif, const struct ddsi_guid *guid) {
 | 
			
		||||
  return btif ? btif->builtintopic_get_tkmap_entry (guid, btif->arg) : NULL;
 | 
			
		||||
}
 | 
			
		||||
inline void builtintopic_write (const struct ddsi_builtin_topic_interface *btif, const struct entity_common *e, nn_wctime_t timestamp, bool alive) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										37
									
								
								src/core/ddsi/include/dds/ddsi/ddsi_guid.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								src/core/ddsi/include/dds/ddsi/ddsi_guid.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,37 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright(c) 2019 ADLINK Technology Limited and others
 | 
			
		||||
 *
 | 
			
		||||
 * This program and the accompanying materials are made available under the
 | 
			
		||||
 * terms of the Eclipse Public License v. 2.0 which is available at
 | 
			
		||||
 * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
 | 
			
		||||
 * v. 1.0 which is available at
 | 
			
		||||
 * http://www.eclipse.org/org/documents/edl-v10.php.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
#ifndef DDSI_GUID_H
 | 
			
		||||
#define DDSI_GUID_H
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
#if defined (__cplusplus)
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
typedef union ddsi_guid_prefix {
 | 
			
		||||
  unsigned char s[12];
 | 
			
		||||
  uint32_t u[3];
 | 
			
		||||
} ddsi_guid_prefix_t;
 | 
			
		||||
typedef union ddsi_entityid {
 | 
			
		||||
  uint32_t u;
 | 
			
		||||
} ddsi_entityid_t;
 | 
			
		||||
typedef struct ddsi_guid {
 | 
			
		||||
  ddsi_guid_prefix_t prefix;
 | 
			
		||||
  ddsi_entityid_t entityid;
 | 
			
		||||
} ddsi_guid_t;
 | 
			
		||||
 | 
			
		||||
#if defined (__cplusplus)
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										67
									
								
								src/core/ddsi/include/dds/ddsi/ddsi_plist_generic.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								src/core/ddsi/include/dds/ddsi/ddsi_plist_generic.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,67 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright(c) 2019 ADLINK Technology Limited and others
 | 
			
		||||
 *
 | 
			
		||||
 * This program and the accompanying materials are made available under the
 | 
			
		||||
 * terms of the Eclipse Public License v. 2.0 which is available at
 | 
			
		||||
 * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
 | 
			
		||||
 * v. 1.0 which is available at
 | 
			
		||||
 * http://www.eclipse.org/org/documents/edl-v10.php.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
#ifndef DDSI_PLIST_GENERIC_H
 | 
			
		||||
#define DDSI_PLIST_GENERIC_H
 | 
			
		||||
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
 | 
			
		||||
#include "dds/export.h"
 | 
			
		||||
 | 
			
		||||
#include "dds/ddsrt/attributes.h"
 | 
			
		||||
 | 
			
		||||
#if defined (__cplusplus)
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* Instructions for the generic serializer (&c) that handles most parameters.
 | 
			
		||||
   The "packed" attribute means single-byte instructions on GCC and Clang. */
 | 
			
		||||
enum pserop {
 | 
			
		||||
  XSTOP,
 | 
			
		||||
  XO, /* octet sequence */
 | 
			
		||||
  XS, /* string */
 | 
			
		||||
  XE1, XE2, XE3, /* enum 0..1, 0..2, 0..3 */
 | 
			
		||||
  Xi, Xix2, Xix3, Xix4, /* int32_t, 1 .. 4 in a row */
 | 
			
		||||
  Xu, Xux2, Xux3, Xux4, Xux5, /* uint32_t, 1 .. 5 in a row */
 | 
			
		||||
  XD, XDx2, /* duration, 1 .. 2 in a row */
 | 
			
		||||
  Xo, Xox2, /* octet, 1 .. 2 in a row */
 | 
			
		||||
  Xb, Xbx2, /* boolean, 1 .. 2 in a row */
 | 
			
		||||
  XbCOND, /* boolean: compare to ignore remainder if false (for use_... flags) */
 | 
			
		||||
  XbPROP, /* boolean: omit in serialized form; skip serialization if false; always true on deserialize */
 | 
			
		||||
  XG, /* GUID */
 | 
			
		||||
  XK, /* keyhash */
 | 
			
		||||
  XQ, /* arbitary non-nested sequence */
 | 
			
		||||
  Xopt, /* remainder is optional on deser, 0-init if not present */
 | 
			
		||||
} ddsrt_attribute_packed;
 | 
			
		||||
 | 
			
		||||
inline bool pserop_seralign_is_1 (enum pserop op) {
 | 
			
		||||
  /* NB: XbPROP is never serialized, so its alignment is irrelevant.  If ever there
 | 
			
		||||
     is a need to allow calling this function when op = XbPROP, it needs to be changed
 | 
			
		||||
     to taking the address of the pserop, and in that case inspect the following
 | 
			
		||||
     operator */
 | 
			
		||||
  assert (op != XbPROP && op != Xopt && op != XSTOP);
 | 
			
		||||
  return (op >= Xo && op <= XK);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DDS_EXPORT void plist_fini_generic (void * __restrict dst, const enum pserop *desc, bool aliased);
 | 
			
		||||
DDS_EXPORT dds_return_t plist_deser_generic (void * __restrict dst, const void * __restrict src, size_t srcsize, bool bswap, const enum pserop * __restrict desc);
 | 
			
		||||
DDS_EXPORT dds_return_t plist_ser_generic (void **dst, size_t *dstsize, const void *src, const enum pserop * __restrict desc);
 | 
			
		||||
DDS_EXPORT dds_return_t plist_unalias_generic (void * __restrict dst, const enum pserop * __restrict desc);
 | 
			
		||||
DDS_EXPORT bool plist_equal_generic (const void *srcx, const void *srcy, const enum pserop * __restrict desc);
 | 
			
		||||
DDS_EXPORT size_t plist_memsize_generic (const enum pserop * __restrict desc);
 | 
			
		||||
 | 
			
		||||
#if defined (__cplusplus)
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										81
									
								
								src/core/ddsi/include/dds/ddsi/ddsi_rhc.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								src/core/ddsi/include/dds/ddsi/ddsi_rhc.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,81 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
 | 
			
		||||
 *
 | 
			
		||||
 * This program and the accompanying materials are made available under the
 | 
			
		||||
 * terms of the Eclipse Public License v. 2.0 which is available at
 | 
			
		||||
 * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
 | 
			
		||||
 * v. 1.0 which is available at
 | 
			
		||||
 * http://www.eclipse.org/org/documents/edl-v10.php.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
#ifndef DDSI_RHC_H
 | 
			
		||||
#define DDSI_RHC_H
 | 
			
		||||
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
 | 
			
		||||
#include "dds/export.h"
 | 
			
		||||
 | 
			
		||||
/* DDS_EXPORT inline i.c.w. __attributes__((visibility...)) and some compilers: */
 | 
			
		||||
#include "dds/ddsrt/attributes.h"
 | 
			
		||||
#include "dds/ddsi/ddsi_guid.h"
 | 
			
		||||
 | 
			
		||||
#if defined (__cplusplus)
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
struct dds_qos;
 | 
			
		||||
struct ddsi_rhc;
 | 
			
		||||
struct ddsi_tkmap_instance;
 | 
			
		||||
struct ddsi_serdata;
 | 
			
		||||
struct ddsi_sertopic;
 | 
			
		||||
 | 
			
		||||
struct ddsi_writer_info
 | 
			
		||||
{
 | 
			
		||||
  ddsi_guid_t guid;
 | 
			
		||||
  bool auto_dispose;
 | 
			
		||||
  int32_t ownership_strength;
 | 
			
		||||
  uint64_t iid;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef void (*ddsi_rhc_free_t) (struct ddsi_rhc *rhc);
 | 
			
		||||
typedef bool (*ddsi_rhc_store_t) (struct ddsi_rhc * __restrict rhc, const struct ddsi_writer_info * __restrict wrinfo, struct ddsi_serdata * __restrict sample, struct ddsi_tkmap_instance * __restrict tk);
 | 
			
		||||
typedef void (*ddsi_rhc_unregister_wr_t) (struct ddsi_rhc * __restrict rhc, const struct ddsi_writer_info * __restrict wrinfo);
 | 
			
		||||
typedef void (*ddsi_rhc_relinquish_ownership_t) (struct ddsi_rhc * __restrict rhc, const uint64_t wr_iid);
 | 
			
		||||
typedef void (*ddsi_rhc_set_qos_t) (struct ddsi_rhc *rhc, const struct dds_qos *qos);
 | 
			
		||||
 | 
			
		||||
struct ddsi_rhc_ops {
 | 
			
		||||
  ddsi_rhc_store_t store;
 | 
			
		||||
  ddsi_rhc_unregister_wr_t unregister_wr;
 | 
			
		||||
  ddsi_rhc_relinquish_ownership_t relinquish_ownership;
 | 
			
		||||
  ddsi_rhc_set_qos_t set_qos;
 | 
			
		||||
  ddsi_rhc_free_t free;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct ddsi_rhc {
 | 
			
		||||
  const struct ddsi_rhc_ops *ops;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
DDS_EXPORT inline bool ddsi_rhc_store (struct ddsi_rhc * __restrict rhc, const struct ddsi_writer_info * __restrict wrinfo, struct ddsi_serdata * __restrict sample, struct ddsi_tkmap_instance * __restrict tk) {
 | 
			
		||||
  return rhc->ops->store (rhc, wrinfo, sample, tk);
 | 
			
		||||
}
 | 
			
		||||
DDS_EXPORT inline void ddsi_rhc_unregister_wr (struct ddsi_rhc * __restrict rhc, const struct ddsi_writer_info * __restrict wrinfo) {
 | 
			
		||||
  rhc->ops->unregister_wr (rhc, wrinfo);
 | 
			
		||||
}
 | 
			
		||||
DDS_EXPORT inline void ddsi_rhc_relinquish_ownership (struct ddsi_rhc * __restrict rhc, const uint64_t wr_iid) {
 | 
			
		||||
  rhc->ops->relinquish_ownership (rhc, wr_iid);
 | 
			
		||||
}
 | 
			
		||||
DDS_EXPORT inline void ddsi_rhc_set_qos (struct ddsi_rhc *rhc, const struct dds_qos *qos) {
 | 
			
		||||
  rhc->ops->set_qos (rhc, qos);
 | 
			
		||||
}
 | 
			
		||||
DDS_EXPORT inline void ddsi_rhc_free (struct ddsi_rhc *rhc) {
 | 
			
		||||
  rhc->ops->free (rhc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if defined (__cplusplus)
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* DDSI_RHC_H */
 | 
			
		||||
| 
						 | 
				
			
			@ -123,6 +123,15 @@ typedef bool (*ddsi_serdata_topicless_to_sample_t) (const struct ddsi_sertopic *
 | 
			
		|||
   computing equijoins across topics much simpler). */
 | 
			
		||||
typedef bool (*ddsi_serdata_eqkey_t) (const struct ddsi_serdata *a, const struct ddsi_serdata *b);
 | 
			
		||||
 | 
			
		||||
/* Print a serdata into the provided buffer (truncating as necessary)
 | 
			
		||||
   - topic is present for supporting printing of "topicless" samples
 | 
			
		||||
   - buf != NULL, bufsize > 0 on input
 | 
			
		||||
   - buf must always be terminated with a nul character on return
 | 
			
		||||
   - returns the number of characters (excluding the terminating 0) needed to print it
 | 
			
		||||
     in full (or, as an optimization, it may pretend that it has printed it in full,
 | 
			
		||||
     returning bufsize-1) if it had to truncate) */
 | 
			
		||||
typedef size_t (*ddsi_serdata_print_t) (const struct ddsi_sertopic *topic, const struct ddsi_serdata *d, char *buf, size_t size);
 | 
			
		||||
 | 
			
		||||
struct ddsi_serdata_ops {
 | 
			
		||||
  ddsi_serdata_eqkey_t eqkey;
 | 
			
		||||
  ddsi_serdata_size_t get_size;
 | 
			
		||||
| 
						 | 
				
			
			@ -136,8 +145,11 @@ struct ddsi_serdata_ops {
 | 
			
		|||
  ddsi_serdata_to_topicless_t to_topicless;
 | 
			
		||||
  ddsi_serdata_topicless_to_sample_t topicless_to_sample;
 | 
			
		||||
  ddsi_serdata_free_t free;
 | 
			
		||||
  ddsi_serdata_print_t print;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define DDSI_SERDATA_HAS_PRINT 1
 | 
			
		||||
 | 
			
		||||
DDS_EXPORT void ddsi_serdata_init (struct ddsi_serdata *d, const struct ddsi_sertopic *tp, enum ddsi_serdata_kind kind);
 | 
			
		||||
 | 
			
		||||
DDS_EXPORT inline struct ddsi_serdata *ddsi_serdata_ref (const struct ddsi_serdata *serdata_const) {
 | 
			
		||||
| 
						 | 
				
			
			@ -195,6 +207,20 @@ DDS_EXPORT inline bool ddsi_serdata_eqkey (const struct ddsi_serdata *a, const s
 | 
			
		|||
  return a->ops->eqkey (a, b);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DDS_EXPORT inline bool ddsi_serdata_print (const struct ddsi_serdata *d, char *buf, size_t size) {
 | 
			
		||||
  return d->ops->print (d->topic, d, buf, size);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DDS_EXPORT inline bool ddsi_serdata_print_topicless (const struct ddsi_sertopic *topic, const struct ddsi_serdata *d, char *buf, size_t size) {
 | 
			
		||||
  if (d->ops->print)
 | 
			
		||||
    return d->ops->print (topic, d, buf, size);
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
    buf[0] = 0;
 | 
			
		||||
    return 0;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if defined (__cplusplus)
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,6 +19,7 @@ typedef struct {
 | 
			
		|||
  uint8_t id[2];
 | 
			
		||||
} nn_vendorid_t;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* All existing vendor codes have the major part equal to 1 (and this will probably be true for a long, long time) */
 | 
			
		||||
#define NN_VENDORID_MINOR_RTI                0x01
 | 
			
		||||
#define NN_VENDORID_MINOR_PRISMTECH_OSPL     0x02
 | 
			
		||||
| 
						 | 
				
			
			@ -38,8 +39,15 @@ typedef struct {
 | 
			
		|||
#define NN_VENDORID_MINOR_ECLIPSE            0x10
 | 
			
		||||
#define NN_VENDORID_MINOR_PRISMTECH_CLOUD    0x20
 | 
			
		||||
 | 
			
		||||
#if defined(_WIN32) && defined(__cplusplus)
 | 
			
		||||
#define NN_VENDORID(vendor) {{ 0x01, NN_VENDORID_MINOR_##vendor }}
 | 
			
		||||
#define NN_VENDORID_UNKNOWN {{ 0x00, 0x00 }}
 | 
			
		||||
#else
 | 
			
		||||
#define NN_VENDORID(vendor) ((nn_vendorid_t) {{ 0x01, NN_VENDORID_MINOR_##vendor }})
 | 
			
		||||
#define NN_VENDORID_UNKNOWN ((nn_vendorid_t) {{ 0x00, 0x00 }})
 | 
			
		||||
#define NN_VENDORID_ECLIPSE ((nn_vendorid_t) {{ 0x01, 0x10 }})
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define NN_VENDORID_ECLIPSE NN_VENDORID (ECLIPSE)
 | 
			
		||||
 | 
			
		||||
#if defined (__cplusplus)
 | 
			
		||||
extern "C" {
 | 
			
		||||
| 
						 | 
				
			
			@ -49,32 +57,32 @@ inline bool vendor_equals (nn_vendorid_t a, nn_vendorid_t b) {
 | 
			
		|||
  return ((a.id[0] << 8) | a.id[1]) == ((b.id[0] << 8) | b.id[1]);
 | 
			
		||||
}
 | 
			
		||||
inline bool vendor_is_eclipse (nn_vendorid_t vendor) {
 | 
			
		||||
  return vendor_equals (vendor, NN_VENDORID_ECLIPSE);
 | 
			
		||||
  return vendor_equals (vendor, NN_VENDORID (ECLIPSE));
 | 
			
		||||
}
 | 
			
		||||
inline bool vendor_is_rti (nn_vendorid_t vendor) {
 | 
			
		||||
  return vendor_equals (vendor, (nn_vendorid_t) {{ 0x01, NN_VENDORID_MINOR_RTI }});
 | 
			
		||||
  return vendor_equals (vendor, NN_VENDORID (RTI));
 | 
			
		||||
}
 | 
			
		||||
inline bool vendor_is_opensplice (nn_vendorid_t vendor) {
 | 
			
		||||
  return vendor_equals (vendor, (nn_vendorid_t) {{ 0x01, NN_VENDORID_MINOR_PRISMTECH_OSPL }});
 | 
			
		||||
  return vendor_equals (vendor, NN_VENDORID (PRISMTECH_OSPL));
 | 
			
		||||
}
 | 
			
		||||
inline bool vendor_is_twinoaks (nn_vendorid_t vendor) {
 | 
			
		||||
  return vendor_equals (vendor, (nn_vendorid_t) {{ 0x01, NN_VENDORID_MINOR_TWINOAKS }});
 | 
			
		||||
  return vendor_equals (vendor, NN_VENDORID (TWINOAKS));
 | 
			
		||||
}
 | 
			
		||||
inline bool vendor_is_eprosima (nn_vendorid_t vendor) {
 | 
			
		||||
  return vendor_equals (vendor, (nn_vendorid_t) {{ 0x01, NN_VENDORID_MINOR_EPROSIMA }});
 | 
			
		||||
  return vendor_equals (vendor, NN_VENDORID (EPROSIMA));
 | 
			
		||||
}
 | 
			
		||||
inline bool vendor_is_cloud (nn_vendorid_t vendor) {
 | 
			
		||||
  return vendor_equals (vendor, (nn_vendorid_t) {{ 0x01, NN_VENDORID_MINOR_PRISMTECH_CLOUD }});
 | 
			
		||||
  return vendor_equals (vendor, NN_VENDORID (PRISMTECH_CLOUD));
 | 
			
		||||
}
 | 
			
		||||
inline bool vendor_is_eclipse_or_opensplice (nn_vendorid_t vendor) {
 | 
			
		||||
  return vendor_is_eclipse (vendor) | vendor_is_opensplice (vendor);
 | 
			
		||||
}
 | 
			
		||||
inline bool vendor_is_prismtech (nn_vendorid_t vendor) {
 | 
			
		||||
  return (vendor_equals (vendor, (nn_vendorid_t) {{ 0x01, NN_VENDORID_MINOR_PRISMTECH_OSPL }}) ||
 | 
			
		||||
          vendor_equals (vendor, (nn_vendorid_t) {{ 0x01, NN_VENDORID_MINOR_PRISMTECH_LITE }}) ||
 | 
			
		||||
          vendor_equals (vendor, (nn_vendorid_t) {{ 0x01, NN_VENDORID_MINOR_PRISMTECH_GATEWAY }}) ||
 | 
			
		||||
          vendor_equals (vendor, (nn_vendorid_t) {{ 0x01, NN_VENDORID_MINOR_PRISMTECH_JAVA }}) ||
 | 
			
		||||
          vendor_equals (vendor, (nn_vendorid_t) {{ 0x01, NN_VENDORID_MINOR_PRISMTECH_CLOUD }}));
 | 
			
		||||
  return (vendor_equals (vendor, NN_VENDORID (PRISMTECH_OSPL)) ||
 | 
			
		||||
          vendor_equals (vendor, NN_VENDORID (PRISMTECH_LITE)) ||
 | 
			
		||||
          vendor_equals (vendor, NN_VENDORID (PRISMTECH_GATEWAY)) ||
 | 
			
		||||
          vendor_equals (vendor, NN_VENDORID (PRISMTECH_JAVA)) ||
 | 
			
		||||
          vendor_equals (vendor, NN_VENDORID (PRISMTECH_CLOUD)));
 | 
			
		||||
}
 | 
			
		||||
inline bool vendor_is_eclipse_or_prismtech (nn_vendorid_t vendor) {
 | 
			
		||||
  return vendor_is_eclipse (vendor) || vendor_is_prismtech (vendor);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -88,12 +88,12 @@ inline void bswapSN (nn_sequence_number_t *sn)
 | 
			
		|||
#define fromBE8u(x) (x)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
nn_guid_prefix_t nn_hton_guid_prefix (nn_guid_prefix_t p);
 | 
			
		||||
nn_guid_prefix_t nn_ntoh_guid_prefix (nn_guid_prefix_t p);
 | 
			
		||||
nn_entityid_t nn_hton_entityid (nn_entityid_t e);
 | 
			
		||||
nn_entityid_t nn_ntoh_entityid (nn_entityid_t e);
 | 
			
		||||
nn_guid_t nn_hton_guid (nn_guid_t g);
 | 
			
		||||
nn_guid_t nn_ntoh_guid (nn_guid_t g);
 | 
			
		||||
ddsi_guid_prefix_t nn_hton_guid_prefix (ddsi_guid_prefix_t p);
 | 
			
		||||
ddsi_guid_prefix_t nn_ntoh_guid_prefix (ddsi_guid_prefix_t p);
 | 
			
		||||
ddsi_entityid_t nn_hton_entityid (ddsi_entityid_t e);
 | 
			
		||||
ddsi_entityid_t nn_ntoh_entityid (ddsi_entityid_t e);
 | 
			
		||||
ddsi_guid_t nn_hton_guid (ddsi_guid_t g);
 | 
			
		||||
ddsi_guid_t nn_ntoh_guid (ddsi_guid_t g);
 | 
			
		||||
 | 
			
		||||
void bswap_sequence_number_set_hdr (nn_sequence_number_set_header_t *snset);
 | 
			
		||||
void bswap_sequence_number_set_bitmap (nn_sequence_number_set_header_t *snset, uint32_t *bits);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -393,7 +393,7 @@ struct config
 | 
			
		|||
 | 
			
		||||
struct cfgst;
 | 
			
		||||
 | 
			
		||||
struct cfgst *config_init (const char *configfile, struct config *cfg, uint32_t domid);
 | 
			
		||||
struct cfgst *config_init (const char *config, struct config *cfg, uint32_t domid) ddsrt_nonnull((1,2));
 | 
			
		||||
void config_print_cfgst (struct cfgst *cfgst, const struct ddsrt_log_cfg *logcfg);
 | 
			
		||||
void config_free_source_info (struct cfgst *cfgst);
 | 
			
		||||
void config_fini (struct cfgst *cfgst);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -36,7 +36,7 @@ int sedp_dispose_unregister_reader (struct reader *rd);
 | 
			
		|||
int sedp_write_topic (struct participant *pp, const struct nn_plist *datap);
 | 
			
		||||
int sedp_write_cm_participant (struct participant *pp, int alive);
 | 
			
		||||
 | 
			
		||||
int builtins_dqueue_handler (const struct nn_rsample_info *sampleinfo, const struct nn_rdata *fragchain, const nn_guid_t *rdguid, void *qarg);
 | 
			
		||||
int builtins_dqueue_handler (const struct nn_rsample_info *sampleinfo, const struct nn_rdata *fragchain, const ddsi_guid_t *rdguid, void *qarg);
 | 
			
		||||
 | 
			
		||||
#if defined (__cplusplus)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -59,12 +59,12 @@ typedef void (*status_cb_t) (void *entity, const status_cb_data_t *data);
 | 
			
		|||
 | 
			
		||||
struct prd_wr_match {
 | 
			
		||||
  ddsrt_avl_node_t avlnode;
 | 
			
		||||
  nn_guid_t wr_guid;
 | 
			
		||||
  ddsi_guid_t wr_guid;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct rd_pwr_match {
 | 
			
		||||
  ddsrt_avl_node_t avlnode;
 | 
			
		||||
  nn_guid_t pwr_guid;
 | 
			
		||||
  ddsi_guid_t pwr_guid;
 | 
			
		||||
#ifdef DDSI_INCLUDE_SSM
 | 
			
		||||
  nn_locator_t ssm_mc_loc;
 | 
			
		||||
  nn_locator_t ssm_src_loc;
 | 
			
		||||
| 
						 | 
				
			
			@ -73,17 +73,17 @@ struct rd_pwr_match {
 | 
			
		|||
 | 
			
		||||
struct wr_rd_match {
 | 
			
		||||
  ddsrt_avl_node_t avlnode;
 | 
			
		||||
  nn_guid_t rd_guid;
 | 
			
		||||
  ddsi_guid_t rd_guid;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct rd_wr_match {
 | 
			
		||||
  ddsrt_avl_node_t avlnode;
 | 
			
		||||
  nn_guid_t wr_guid;
 | 
			
		||||
  ddsi_guid_t wr_guid;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct wr_prd_match {
 | 
			
		||||
  ddsrt_avl_node_t avlnode;
 | 
			
		||||
  nn_guid_t prd_guid; /* guid of the proxy reader */
 | 
			
		||||
  ddsi_guid_t prd_guid; /* guid of the proxy reader */
 | 
			
		||||
  unsigned assumed_in_sync: 1; /* set to 1 upon receipt of ack not nack'ing msgs */
 | 
			
		||||
  unsigned has_replied_to_hb: 1; /* we must keep sending HBs until all readers have this set */
 | 
			
		||||
  unsigned all_have_replied_to_hb: 1; /* true iff 'has_replied_to_hb' for all readers in subtree */
 | 
			
		||||
| 
						 | 
				
			
			@ -91,8 +91,8 @@ struct wr_prd_match {
 | 
			
		|||
  seqno_t min_seq; /* smallest ack'd seq nr in subtree */
 | 
			
		||||
  seqno_t max_seq; /* sort-of highest ack'd seq nr in subtree (see augment function) */
 | 
			
		||||
  seqno_t seq; /* highest acknowledged seq nr */
 | 
			
		||||
  int num_reliable_readers_where_seq_equals_max;
 | 
			
		||||
  nn_guid_t arbitrary_unacked_reader;
 | 
			
		||||
  int32_t num_reliable_readers_where_seq_equals_max;
 | 
			
		||||
  ddsi_guid_t arbitrary_unacked_reader;
 | 
			
		||||
  nn_count_t next_acknack; /* next acceptable acknack sequence number */
 | 
			
		||||
  nn_count_t next_nackfrag; /* next acceptable nackfrag sequence number */
 | 
			
		||||
  nn_etime_t t_acknack_accepted; /* (local) time an acknack was last accepted */
 | 
			
		||||
| 
						 | 
				
			
			@ -110,7 +110,7 @@ enum pwr_rd_match_syncstate {
 | 
			
		|||
 | 
			
		||||
struct pwr_rd_match {
 | 
			
		||||
  ddsrt_avl_node_t avlnode;
 | 
			
		||||
  nn_guid_t rd_guid;
 | 
			
		||||
  ddsi_guid_t rd_guid;
 | 
			
		||||
  nn_mtime_t tcreate;
 | 
			
		||||
  nn_count_t count; /* most recent acknack sequence number */
 | 
			
		||||
  nn_count_t next_heartbeat; /* next acceptable heartbeat (see also add_proxy_writer_to_reader) */
 | 
			
		||||
| 
						 | 
				
			
			@ -134,7 +134,7 @@ struct ddsi_tkmap_instance;
 | 
			
		|||
 | 
			
		||||
struct entity_common {
 | 
			
		||||
  enum entity_kind kind;
 | 
			
		||||
  nn_guid_t guid;
 | 
			
		||||
  ddsi_guid_t guid;
 | 
			
		||||
  nn_wctime_t tupdate; /* timestamp of last update */
 | 
			
		||||
  char *name;
 | 
			
		||||
  uint64_t iid;
 | 
			
		||||
| 
						 | 
				
			
			@ -188,7 +188,7 @@ struct participant
 | 
			
		|||
 | 
			
		||||
struct endpoint_common {
 | 
			
		||||
  struct participant *pp;
 | 
			
		||||
  nn_guid_t group_guid;
 | 
			
		||||
  ddsi_guid_t group_guid;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct generic_endpoint { /* FIXME: currently only local endpoints; proxies use entity_common + proxy_endpoint common */
 | 
			
		||||
| 
						 | 
				
			
			@ -198,6 +198,7 @@ struct generic_endpoint { /* FIXME: currently only local endpoints; proxies use
 | 
			
		|||
 | 
			
		||||
enum writer_state {
 | 
			
		||||
  WRST_OPERATIONAL, /* normal situation */
 | 
			
		||||
  WRST_INTERRUPT, /* will be deleted, unblock throttle_writer but do not do anything further */
 | 
			
		||||
  WRST_LINGERING, /* writer deletion has been requested but still has unack'd data */
 | 
			
		||||
  WRST_DELETING /* writer is actually being deleted (removed from hash table) */
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -259,7 +260,7 @@ struct writer
 | 
			
		|||
  uint32_t whc_low, whc_high; /* watermarks for WHC in bytes (counting only unack'd data) */
 | 
			
		||||
  nn_etime_t t_rexmit_end; /* time of last 1->0 transition of "retransmitting" */
 | 
			
		||||
  nn_etime_t t_whc_high_upd; /* time "whc_high" was last updated for controlled ramp-up of throughput */
 | 
			
		||||
  int num_reliable_readers; /* number of matching reliable PROXY readers */
 | 
			
		||||
  int32_t num_reliable_readers; /* number of matching reliable PROXY readers */
 | 
			
		||||
  ddsrt_avl_tree_t readers; /* all matching PROXY readers, see struct wr_prd_match */
 | 
			
		||||
  ddsrt_avl_tree_t local_readers; /* all matching LOCAL readers, see struct wr_rd_match */
 | 
			
		||||
#ifdef DDSI_INCLUDE_NETWORK_PARTITIONS
 | 
			
		||||
| 
						 | 
				
			
			@ -281,7 +282,7 @@ struct reader
 | 
			
		|||
  struct endpoint_common c;
 | 
			
		||||
  status_cb_t status_cb;
 | 
			
		||||
  void * status_cb_entity;
 | 
			
		||||
  struct rhc * rhc; /* reader history, tracks registrations and data */
 | 
			
		||||
  struct ddsi_rhc * rhc; /* reader history, tracks registrations and data */
 | 
			
		||||
  struct dds_qos *xqos;
 | 
			
		||||
  unsigned reliable: 1; /* 1 iff reader is reliable */
 | 
			
		||||
  unsigned handle_as_transient_local: 1; /* 1 iff reader wants historical data from proxy writers */
 | 
			
		||||
| 
						 | 
				
			
			@ -306,7 +307,7 @@ struct proxy_participant
 | 
			
		|||
  nn_vendorid_t vendor; /* vendor code from discovery */
 | 
			
		||||
  unsigned bes; /* built-in endpoint set */
 | 
			
		||||
  unsigned prismtech_bes; /* prismtech-specific extension of built-in endpoints set */
 | 
			
		||||
  nn_guid_t privileged_pp_guid; /* if this PP depends on another PP for its SEDP writing */
 | 
			
		||||
  ddsi_guid_t privileged_pp_guid; /* if this PP depends on another PP for its SEDP writing */
 | 
			
		||||
  struct nn_plist *plist; /* settings/QoS for this participant */
 | 
			
		||||
  ddsrt_atomic_voidp_t lease; /* lease object for this participant, for automatic leases */
 | 
			
		||||
  struct addrset *as_default; /* default address set to use for user data traffic */
 | 
			
		||||
| 
						 | 
				
			
			@ -333,7 +334,7 @@ struct proxy_participant
 | 
			
		|||
   participant. */
 | 
			
		||||
struct proxy_group {
 | 
			
		||||
  ddsrt_avl_node_t avlnode;
 | 
			
		||||
  nn_guid_t guid;
 | 
			
		||||
  ddsi_guid_t guid;
 | 
			
		||||
  char *name;
 | 
			
		||||
  struct proxy_participant *proxypp; /* uncounted backref to proxy participant */
 | 
			
		||||
  struct dds_qos *xqos; /* publisher/subscriber QoS */
 | 
			
		||||
| 
						 | 
				
			
			@ -345,9 +346,8 @@ struct proxy_endpoint_common
 | 
			
		|||
  struct proxy_endpoint_common *next_ep; /* next \ endpoint belonging to this proxy participant */
 | 
			
		||||
  struct proxy_endpoint_common *prev_ep; /* prev / -- this is in arbitrary ordering */
 | 
			
		||||
  struct dds_qos *xqos; /* proxy endpoint QoS lives here; FIXME: local ones should have it moved to common as well */
 | 
			
		||||
  struct ddsi_sertopic * topic; /* topic may be NULL: for built-ins, but also for never-yet matched proxies (so we don't have to know the topic; when we match, we certainly do know) */
 | 
			
		||||
  struct addrset *as; /* address set to use for communicating with this endpoint */
 | 
			
		||||
  nn_guid_t group_guid; /* 0:0:0:0 if not available */
 | 
			
		||||
  ddsi_guid_t group_guid; /* 0:0:0:0 if not available */
 | 
			
		||||
  nn_vendorid_t vendor; /* cached from proxypp->vendor */
 | 
			
		||||
  seqno_t seq; /* sequence number of most recent SEDP message */
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -356,8 +356,8 @@ struct proxy_writer {
 | 
			
		|||
  struct entity_common e;
 | 
			
		||||
  struct proxy_endpoint_common c;
 | 
			
		||||
  ddsrt_avl_tree_t readers; /* matching LOCAL readers, see pwr_rd_match */
 | 
			
		||||
  int n_reliable_readers; /* number of those that are reliable */
 | 
			
		||||
  int n_readers_out_of_sync; /* number of those that require special handling (accepting historical data, waiting for historical data set to become complete) */
 | 
			
		||||
  int32_t n_reliable_readers; /* number of those that are reliable */
 | 
			
		||||
  int32_t n_readers_out_of_sync; /* number of those that require special handling (accepting historical data, waiting for historical data set to become complete) */
 | 
			
		||||
  seqno_t last_seq; /* highest known seq published by the writer, not last delivered */
 | 
			
		||||
  uint32_t last_fragnum; /* last known frag for last_seq, or ~0u if last_seq not partial */
 | 
			
		||||
  nn_count_t nackfragcount; /* last nackfrag seq number */
 | 
			
		||||
| 
						 | 
				
			
			@ -400,17 +400,18 @@ extern const ddsrt_avl_treedef_t deleted_participants_treedef;
 | 
			
		|||
#define DPG_LOCAL 1
 | 
			
		||||
#define DPG_REMOTE 2
 | 
			
		||||
struct deleted_participants_admin;
 | 
			
		||||
struct deleted_participants_admin *deleted_participants_admin_new (int64_t delay);
 | 
			
		||||
struct deleted_participants_admin *deleted_participants_admin_new (const ddsrt_log_cfg_t *logcfg, int64_t delay);
 | 
			
		||||
void deleted_participants_admin_free (struct deleted_participants_admin *admin);
 | 
			
		||||
int is_deleted_participant_guid (struct deleted_participants_admin *admin, const struct nn_guid *guid, unsigned for_what);
 | 
			
		||||
int is_deleted_participant_guid (struct deleted_participants_admin *admin, const struct ddsi_guid *guid, unsigned for_what);
 | 
			
		||||
 | 
			
		||||
nn_entityid_t to_entityid (unsigned u);
 | 
			
		||||
int is_builtin_entityid (nn_entityid_t id, nn_vendorid_t vendorid);
 | 
			
		||||
int is_builtin_endpoint (nn_entityid_t id, nn_vendorid_t vendorid);
 | 
			
		||||
bool is_null_guid (const ddsi_guid_t *guid);
 | 
			
		||||
ddsi_entityid_t to_entityid (unsigned u);
 | 
			
		||||
int is_builtin_entityid (ddsi_entityid_t id, nn_vendorid_t vendorid);
 | 
			
		||||
int is_builtin_endpoint (ddsi_entityid_t id, nn_vendorid_t vendorid);
 | 
			
		||||
bool is_local_orphan_endpoint (const struct entity_common *e);
 | 
			
		||||
int is_writer_entityid (nn_entityid_t id);
 | 
			
		||||
int is_reader_entityid (nn_entityid_t id);
 | 
			
		||||
int is_keyed_endpoint_entityid (nn_entityid_t id);
 | 
			
		||||
int is_writer_entityid (ddsi_entityid_t id);
 | 
			
		||||
int is_reader_entityid (ddsi_entityid_t id);
 | 
			
		||||
int is_keyed_endpoint_entityid (ddsi_entityid_t id);
 | 
			
		||||
nn_vendorid_t get_entity_vendorid (const struct entity_common *e);
 | 
			
		||||
 | 
			
		||||
/* Interface for glue code between the OpenSplice kernel and the DDSI
 | 
			
		||||
| 
						 | 
				
			
			@ -491,7 +492,7 @@ nn_vendorid_t get_entity_vendorid (const struct entity_common *e);
 | 
			
		|||
 * @retval DDS_RETCODE_OUT_OF_RESOURCES
 | 
			
		||||
 *               The configured maximum number of participants has been reached.
 | 
			
		||||
 */
 | 
			
		||||
dds_return_t new_participant_guid (const nn_guid_t *ppguid, struct q_globals *gv, unsigned flags, const struct nn_plist *plist);
 | 
			
		||||
dds_return_t new_participant_guid (const ddsi_guid_t *ppguid, struct q_globals *gv, unsigned flags, const struct nn_plist *plist);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Create a new participant in the domain.  See also new_participant_guid.
 | 
			
		||||
| 
						 | 
				
			
			@ -515,7 +516,7 @@ dds_return_t new_participant_guid (const nn_guid_t *ppguid, struct q_globals *gv
 | 
			
		|||
 * @retval DDS_RETCODE_OUT_OF_RESOURCES
 | 
			
		||||
 *               The configured maximum number of participants has been reached.
 | 
			
		||||
*/
 | 
			
		||||
dds_return_t new_participant (struct nn_guid *ppguid, struct q_globals *gv, unsigned flags, const struct nn_plist *plist);
 | 
			
		||||
dds_return_t new_participant (struct ddsi_guid *ppguid, struct q_globals *gv, unsigned flags, const struct nn_plist *plist);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Initiate the deletion of the participant:
 | 
			
		||||
| 
						 | 
				
			
			@ -541,9 +542,9 @@ dds_return_t new_participant (struct nn_guid *ppguid, struct q_globals *gv, unsi
 | 
			
		|||
 * @retval DDS_RETCODE_BAD_PARAMETER
 | 
			
		||||
 *               ppguid lookup failed.
 | 
			
		||||
*/
 | 
			
		||||
dds_return_t delete_participant (struct q_globals *gv, const struct nn_guid *ppguid);
 | 
			
		||||
dds_return_t delete_participant (struct q_globals *gv, const struct ddsi_guid *ppguid);
 | 
			
		||||
void update_participant_plist (struct participant *pp, const struct nn_plist *plist);
 | 
			
		||||
uint64_t get_entity_instance_id (const struct q_globals *gv, const struct nn_guid *guid);
 | 
			
		||||
uint64_t get_entity_instance_id (const struct q_globals *gv, const struct ddsi_guid *guid);
 | 
			
		||||
 | 
			
		||||
/* To obtain the builtin writer to be used for publishing SPDP, SEDP,
 | 
			
		||||
   PMD stuff for PP and its endpoints, given the entityid.  If PP has
 | 
			
		||||
| 
						 | 
				
			
			@ -554,9 +555,9 @@ struct writer *get_builtin_writer (const struct participant *pp, unsigned entity
 | 
			
		|||
   GUID "ppguid". May return NULL if participant unknown or
 | 
			
		||||
   writer/reader already known. */
 | 
			
		||||
 | 
			
		||||
dds_return_t new_writer (struct writer **wr_out, struct q_globals *gv, struct nn_guid *wrguid, const struct nn_guid *group_guid, const struct nn_guid *ppguid, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct whc * whc, status_cb_t status_cb, void *status_cb_arg);
 | 
			
		||||
dds_return_t new_writer (struct writer **wr_out, struct q_globals *gv, struct ddsi_guid *wrguid, const struct ddsi_guid *group_guid, const struct ddsi_guid *ppguid, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct whc * whc, status_cb_t status_cb, void *status_cb_arg);
 | 
			
		||||
 | 
			
		||||
dds_return_t new_reader (struct reader **rd_out, struct q_globals *gv, struct nn_guid *rdguid, const struct nn_guid *group_guid, const struct nn_guid *ppguid, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct rhc * rhc, status_cb_t status_cb, void *status_cb_arg);
 | 
			
		||||
dds_return_t new_reader (struct reader **rd_out, struct q_globals *gv, struct ddsi_guid *rdguid, const struct ddsi_guid *group_guid, const struct ddsi_guid *ppguid, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct ddsi_rhc * rhc, status_cb_t status_cb, void *status_cb_arg);
 | 
			
		||||
 | 
			
		||||
void update_reader_qos (struct reader *rd, const struct dds_qos *xqos);
 | 
			
		||||
void update_writer_qos (struct writer *wr, const struct dds_qos *xqos);
 | 
			
		||||
| 
						 | 
				
			
			@ -569,16 +570,17 @@ int writer_must_have_hb_scheduled (const struct writer *wr, const struct whc_sta
 | 
			
		|||
void writer_set_retransmitting (struct writer *wr);
 | 
			
		||||
void writer_clear_retransmitting (struct writer *wr);
 | 
			
		||||
 | 
			
		||||
dds_return_t delete_writer (struct q_globals *gv, const struct nn_guid *guid);
 | 
			
		||||
dds_return_t delete_writer_nolinger (struct q_globals *gv, const struct nn_guid *guid);
 | 
			
		||||
dds_return_t unblock_throttled_writer (struct q_globals *gv, const struct ddsi_guid *guid);
 | 
			
		||||
dds_return_t delete_writer (struct q_globals *gv, const struct ddsi_guid *guid);
 | 
			
		||||
dds_return_t delete_writer_nolinger (struct q_globals *gv, const struct ddsi_guid *guid);
 | 
			
		||||
dds_return_t delete_writer_nolinger_locked (struct writer *wr);
 | 
			
		||||
 | 
			
		||||
dds_return_t delete_reader (struct q_globals *gv, const struct nn_guid *guid);
 | 
			
		||||
dds_return_t delete_reader (struct q_globals *gv, const struct ddsi_guid *guid);
 | 
			
		||||
 | 
			
		||||
struct local_orphan_writer {
 | 
			
		||||
  struct writer wr;
 | 
			
		||||
};
 | 
			
		||||
struct local_orphan_writer *new_local_orphan_writer (struct q_globals *gv, nn_entityid_t entityid, struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct whc *whc);
 | 
			
		||||
struct local_orphan_writer *new_local_orphan_writer (struct q_globals *gv, ddsi_entityid_t entityid, struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct whc *whc);
 | 
			
		||||
void delete_local_orphan_writer (struct local_orphan_writer *wr);
 | 
			
		||||
 | 
			
		||||
/* To create or delete a new proxy participant: "guid" MUST have the
 | 
			
		||||
| 
						 | 
				
			
			@ -605,8 +607,8 @@ void delete_local_orphan_writer (struct local_orphan_writer *wr);
 | 
			
		|||
/* Set when this proxy participant is not to be announced on the built-in topics yet */
 | 
			
		||||
#define CF_PROXYPP_NO_SPDP                     (1 << 3)
 | 
			
		||||
 | 
			
		||||
void new_proxy_participant (struct q_globals *gv, const struct nn_guid *guid, unsigned bes, unsigned prismtech_bes, const struct nn_guid *privileged_pp_guid, struct addrset *as_default, struct addrset *as_meta, const struct nn_plist *plist, dds_duration_t tlease_dur, nn_vendorid_t vendor, unsigned custom_flags, nn_wctime_t timestamp, seqno_t seq);
 | 
			
		||||
int delete_proxy_participant_by_guid (struct q_globals *gv, const struct nn_guid *guid, nn_wctime_t timestamp, int isimplicit);
 | 
			
		||||
void new_proxy_participant (struct q_globals *gv, const struct ddsi_guid *guid, unsigned bes, unsigned prismtech_bes, const struct ddsi_guid *privileged_pp_guid, struct addrset *as_default, struct addrset *as_meta, const struct nn_plist *plist, dds_duration_t tlease_dur, nn_vendorid_t vendor, unsigned custom_flags, nn_wctime_t timestamp, seqno_t seq);
 | 
			
		||||
int delete_proxy_participant_by_guid (struct q_globals *gv, const struct ddsi_guid *guid, nn_wctime_t timestamp, int isimplicit);
 | 
			
		||||
 | 
			
		||||
enum update_proxy_participant_source {
 | 
			
		||||
  UPD_PROXYPP_SPDP,
 | 
			
		||||
| 
						 | 
				
			
			@ -621,8 +623,8 @@ void purge_proxy_participants (struct q_globals *gv, const nn_locator_t *loc, bo
 | 
			
		|||
 | 
			
		||||
/* To create a new proxy writer or reader; the proxy participant is
 | 
			
		||||
   determined from the GUID and must exist. */
 | 
			
		||||
  int new_proxy_writer (struct q_globals *gv, const struct nn_guid *ppguid, const struct nn_guid *guid, struct addrset *as, const struct nn_plist *plist, struct nn_dqueue *dqueue, struct xeventq *evq, nn_wctime_t timestamp, seqno_t seq);
 | 
			
		||||
int new_proxy_reader (struct q_globals *gv, const struct nn_guid *ppguid, const struct nn_guid *guid, struct addrset *as, const struct nn_plist *plist, nn_wctime_t timestamp, seqno_t seq
 | 
			
		||||
  int new_proxy_writer (struct q_globals *gv, const struct ddsi_guid *ppguid, const struct ddsi_guid *guid, struct addrset *as, const struct nn_plist *plist, struct nn_dqueue *dqueue, struct xeventq *evq, nn_wctime_t timestamp, seqno_t seq);
 | 
			
		||||
int new_proxy_reader (struct q_globals *gv, const struct ddsi_guid *ppguid, const struct ddsi_guid *guid, struct addrset *as, const struct nn_plist *plist, nn_wctime_t timestamp, seqno_t seq
 | 
			
		||||
#ifdef DDSI_INCLUDE_SSM
 | 
			
		||||
                      , int favours_ssm
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -633,22 +635,24 @@ int new_proxy_reader (struct q_globals *gv, const struct nn_guid *ppguid, const
 | 
			
		|||
   reader or writer. Actual deletion is scheduled in the future, when
 | 
			
		||||
   no outstanding references may still exist (determined by checking
 | 
			
		||||
   thread progress, &c.). */
 | 
			
		||||
int delete_proxy_writer (struct q_globals *gv, const struct nn_guid *guid, nn_wctime_t timestamp, int isimplicit);
 | 
			
		||||
int delete_proxy_reader (struct q_globals *gv, const struct nn_guid *guid, nn_wctime_t timestamp, int isimplicit);
 | 
			
		||||
int delete_proxy_writer (struct q_globals *gv, const struct ddsi_guid *guid, nn_wctime_t timestamp, int isimplicit);
 | 
			
		||||
int delete_proxy_reader (struct q_globals *gv, const struct ddsi_guid *guid, nn_wctime_t timestamp, int isimplicit);
 | 
			
		||||
 | 
			
		||||
void update_proxy_reader (struct proxy_reader *prd, seqno_t seq, struct addrset *as, const struct dds_qos *xqos, nn_wctime_t timestamp);
 | 
			
		||||
void update_proxy_writer (struct proxy_writer *pwr, seqno_t seq, struct addrset *as, const struct dds_qos *xqos, nn_wctime_t timestamp);
 | 
			
		||||
 | 
			
		||||
int new_proxy_group (const struct nn_guid *guid, const char *name, const struct dds_qos *xqos, nn_wctime_t timestamp);
 | 
			
		||||
void delete_proxy_group (struct ephash *guid_hash, const struct nn_guid *guid, nn_wctime_t timestamp, int isimplicit);
 | 
			
		||||
int new_proxy_group (const struct ddsi_guid *guid, const char *name, const struct dds_qos *xqos, nn_wctime_t timestamp);
 | 
			
		||||
void delete_proxy_group (struct ephash *guid_hash, const struct ddsi_guid *guid, nn_wctime_t timestamp, int isimplicit);
 | 
			
		||||
 | 
			
		||||
/* Call this to empty all address sets of all writers to stop all outgoing traffic, or to
 | 
			
		||||
   rebuild them all (which only makes sense after previously having emptied them all). */
 | 
			
		||||
void rebuild_or_clear_writer_addrsets(struct q_globals *gv, int rebuild);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void local_reader_ary_setfastpath_ok (struct local_reader_ary *x, bool fastpath_ok);
 | 
			
		||||
 | 
			
		||||
struct ddsi_writer_info;
 | 
			
		||||
DDS_EXPORT void ddsi_make_writer_info(struct ddsi_writer_info *wrinfo, const struct entity_common *e, const struct dds_qos *xqos);
 | 
			
		||||
 | 
			
		||||
#if defined (__cplusplus)
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -25,7 +25,7 @@ struct writer;
 | 
			
		|||
struct proxy_participant;
 | 
			
		||||
struct proxy_reader;
 | 
			
		||||
struct proxy_writer;
 | 
			
		||||
struct nn_guid;
 | 
			
		||||
struct ddsi_guid;
 | 
			
		||||
 | 
			
		||||
  enum entity_kind {
 | 
			
		||||
    EK_PARTICIPANT,
 | 
			
		||||
| 
						 | 
				
			
			@ -80,15 +80,15 @@ void ephash_remove_reader_guid (struct ephash *eh, struct reader *rd);
 | 
			
		|||
void ephash_remove_proxy_writer_guid (struct ephash *eh, struct proxy_writer *pwr);
 | 
			
		||||
void ephash_remove_proxy_reader_guid (struct ephash *eh, struct proxy_reader *prd);
 | 
			
		||||
 | 
			
		||||
void *ephash_lookup_guid_untyped (const struct ephash *eh, const struct nn_guid *guid);
 | 
			
		||||
void *ephash_lookup_guid (const struct ephash *eh, const struct nn_guid *guid, enum entity_kind kind);
 | 
			
		||||
void *ephash_lookup_guid_untyped (const struct ephash *eh, const struct ddsi_guid *guid);
 | 
			
		||||
void *ephash_lookup_guid (const struct ephash *eh, const struct ddsi_guid *guid, enum entity_kind kind);
 | 
			
		||||
 | 
			
		||||
struct participant *ephash_lookup_participant_guid (const struct ephash *eh, const struct nn_guid *guid);
 | 
			
		||||
struct proxy_participant *ephash_lookup_proxy_participant_guid (const struct ephash *eh, const struct nn_guid *guid);
 | 
			
		||||
struct writer *ephash_lookup_writer_guid (const struct ephash *eh, const struct nn_guid *guid);
 | 
			
		||||
struct reader *ephash_lookup_reader_guid (const struct ephash *eh, const struct nn_guid *guid);
 | 
			
		||||
struct proxy_writer *ephash_lookup_proxy_writer_guid (const struct ephash *eh, const struct nn_guid *guid);
 | 
			
		||||
struct proxy_reader *ephash_lookup_proxy_reader_guid (const struct ephash *eh, const struct nn_guid *guid);
 | 
			
		||||
struct participant *ephash_lookup_participant_guid (const struct ephash *eh, const struct ddsi_guid *guid);
 | 
			
		||||
struct proxy_participant *ephash_lookup_proxy_participant_guid (const struct ephash *eh, const struct ddsi_guid *guid);
 | 
			
		||||
struct writer *ephash_lookup_writer_guid (const struct ephash *eh, const struct ddsi_guid *guid);
 | 
			
		||||
struct reader *ephash_lookup_reader_guid (const struct ephash *eh, const struct ddsi_guid *guid);
 | 
			
		||||
struct proxy_writer *ephash_lookup_proxy_writer_guid (const struct ephash *eh, const struct ddsi_guid *guid);
 | 
			
		||||
struct proxy_reader *ephash_lookup_proxy_reader_guid (const struct ephash *eh, const struct ddsi_guid *guid);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Enumeration of entries in the hash table:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -158,7 +158,7 @@ struct q_globals {
 | 
			
		|||
 | 
			
		||||
  /* GUID to be used in next call to new_participant; also protected
 | 
			
		||||
     by privileged_pp_lock */
 | 
			
		||||
  struct nn_guid next_ppguid;
 | 
			
		||||
  struct ddsi_guid ppguid_base;
 | 
			
		||||
 | 
			
		||||
  /* number of up, non-loopback, IPv4/IPv6 interfaces, the index of
 | 
			
		||||
     the selected/preferred one, and the discovered interfaces. */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -116,7 +116,7 @@ typedef struct nn_prismtech_participant_version_info
 | 
			
		|||
} nn_prismtech_participant_version_info_t;
 | 
			
		||||
 | 
			
		||||
typedef struct nn_prismtech_eotgroup_tid {
 | 
			
		||||
  nn_entityid_t writer_entityid;
 | 
			
		||||
  ddsi_entityid_t writer_entityid;
 | 
			
		||||
  uint32_t transactionId;
 | 
			
		||||
} nn_prismtech_eotgroup_tid_t;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -140,9 +140,9 @@ typedef struct nn_plist {
 | 
			
		|||
  uint32_t participant_builtin_endpoints;
 | 
			
		||||
  dds_duration_t participant_lease_duration;
 | 
			
		||||
  /* nn_content_filter_property_t content_filter_property; */
 | 
			
		||||
  nn_guid_t participant_guid;
 | 
			
		||||
  nn_guid_t endpoint_guid;
 | 
			
		||||
  nn_guid_t group_guid;
 | 
			
		||||
  ddsi_guid_t participant_guid;
 | 
			
		||||
  ddsi_guid_t endpoint_guid;
 | 
			
		||||
  ddsi_guid_t group_guid;
 | 
			
		||||
#if 0 /* reserved, rather than NIY */
 | 
			
		||||
  nn_entityid_t participant_entityid;
 | 
			
		||||
  nn_entityid_t group_entityid;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,6 +13,7 @@
 | 
			
		|||
#define NN_PROTOCOL_H
 | 
			
		||||
 | 
			
		||||
#include "dds/ddsrt/endian.h"
 | 
			
		||||
#include "dds/ddsrt/misc.h"
 | 
			
		||||
#include "dds/ddsi/q_feature_check.h"
 | 
			
		||||
 | 
			
		||||
#include "dds/ddsi/q_rtps.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -115,7 +116,7 @@ typedef struct Header {
 | 
			
		|||
  nn_protocolid_t protocol;
 | 
			
		||||
  nn_protocol_version_t version;
 | 
			
		||||
  nn_vendorid_t vendorid;
 | 
			
		||||
  nn_guid_prefix_t guid_prefix;
 | 
			
		||||
  ddsi_guid_prefix_t guid_prefix;
 | 
			
		||||
} Header_t;
 | 
			
		||||
#if DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN
 | 
			
		||||
#define NN_PROTOCOLID_AS_UINT32 (((uint32_t)'R' << 0) | ((uint32_t)'T' << 8) | ((uint32_t)'P' << 16) | ((uint32_t)'S' << 24))
 | 
			
		||||
| 
						 | 
				
			
			@ -161,12 +162,12 @@ typedef struct InfoTimestamp {
 | 
			
		|||
 | 
			
		||||
typedef struct EntityId {
 | 
			
		||||
  SubmessageHeader_t smhdr;
 | 
			
		||||
  nn_entityid_t entityid;
 | 
			
		||||
  ddsi_entityid_t entityid;
 | 
			
		||||
} EntityId_t;
 | 
			
		||||
 | 
			
		||||
typedef struct InfoDST {
 | 
			
		||||
  SubmessageHeader_t smhdr;
 | 
			
		||||
  nn_guid_prefix_t guid_prefix;
 | 
			
		||||
  ddsi_guid_prefix_t guid_prefix;
 | 
			
		||||
} InfoDST_t;
 | 
			
		||||
 | 
			
		||||
typedef struct InfoSRC {
 | 
			
		||||
| 
						 | 
				
			
			@ -174,7 +175,7 @@ typedef struct InfoSRC {
 | 
			
		|||
  unsigned unused;
 | 
			
		||||
  nn_protocol_version_t version;
 | 
			
		||||
  nn_vendorid_t vendorid;
 | 
			
		||||
  nn_guid_prefix_t guid_prefix;
 | 
			
		||||
  ddsi_guid_prefix_t guid_prefix;
 | 
			
		||||
} InfoSRC_t;
 | 
			
		||||
 | 
			
		||||
#if DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN
 | 
			
		||||
| 
						 | 
				
			
			@ -196,8 +197,8 @@ typedef struct Data_DataFrag_common {
 | 
			
		|||
  SubmessageHeader_t smhdr;
 | 
			
		||||
  uint16_t extraFlags;
 | 
			
		||||
  uint16_t octetsToInlineQos;
 | 
			
		||||
  nn_entityid_t readerId;
 | 
			
		||||
  nn_entityid_t writerId;
 | 
			
		||||
  ddsi_entityid_t readerId;
 | 
			
		||||
  ddsi_entityid_t writerId;
 | 
			
		||||
  nn_sequence_number_t writerSN;
 | 
			
		||||
} Data_DataFrag_common_t;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -223,26 +224,30 @@ typedef struct MsgLen {
 | 
			
		|||
  uint32_t length;
 | 
			
		||||
} MsgLen_t;
 | 
			
		||||
 | 
			
		||||
DDSRT_WARNING_MSVC_OFF(4200)
 | 
			
		||||
typedef struct AckNack {
 | 
			
		||||
  SubmessageHeader_t smhdr;
 | 
			
		||||
  nn_entityid_t readerId;
 | 
			
		||||
  nn_entityid_t writerId;
 | 
			
		||||
  ddsi_entityid_t readerId;
 | 
			
		||||
  ddsi_entityid_t writerId;
 | 
			
		||||
  nn_sequence_number_set_header_t readerSNState;
 | 
			
		||||
  uint32_t bits[];
 | 
			
		||||
  /* nn_count_t count; */
 | 
			
		||||
} AckNack_t;
 | 
			
		||||
DDSRT_WARNING_MSVC_ON(4200)
 | 
			
		||||
#define ACKNACK_FLAG_FINAL 0x02u
 | 
			
		||||
#define ACKNACK_SIZE(numbits) (offsetof (AckNack_t, bits) + NN_SEQUENCE_NUMBER_SET_BITS_SIZE (numbits) + 4)
 | 
			
		||||
#define ACKNACK_SIZE_MAX ACKNACK_SIZE (256u)
 | 
			
		||||
 | 
			
		||||
DDSRT_WARNING_MSVC_OFF(4200)
 | 
			
		||||
typedef struct Gap {
 | 
			
		||||
  SubmessageHeader_t smhdr;
 | 
			
		||||
  nn_entityid_t readerId;
 | 
			
		||||
  nn_entityid_t writerId;
 | 
			
		||||
  ddsi_entityid_t readerId;
 | 
			
		||||
  ddsi_entityid_t writerId;
 | 
			
		||||
  nn_sequence_number_t gapStart;
 | 
			
		||||
  nn_sequence_number_set_header_t gapList;
 | 
			
		||||
  uint32_t bits[];
 | 
			
		||||
} Gap_t;
 | 
			
		||||
DDSRT_WARNING_MSVC_ON(4200)
 | 
			
		||||
#define GAP_SIZE(numbits) (offsetof (Gap_t, bits) + NN_SEQUENCE_NUMBER_SET_BITS_SIZE (numbits))
 | 
			
		||||
#define GAP_SIZE_MAX GAP_SIZE (256u)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -254,8 +259,8 @@ typedef struct InfoTS {
 | 
			
		|||
 | 
			
		||||
typedef struct Heartbeat {
 | 
			
		||||
  SubmessageHeader_t smhdr;
 | 
			
		||||
  nn_entityid_t readerId;
 | 
			
		||||
  nn_entityid_t writerId;
 | 
			
		||||
  ddsi_entityid_t readerId;
 | 
			
		||||
  ddsi_entityid_t writerId;
 | 
			
		||||
  nn_sequence_number_t firstSN;
 | 
			
		||||
  nn_sequence_number_t lastSN;
 | 
			
		||||
  nn_count_t count;
 | 
			
		||||
| 
						 | 
				
			
			@ -265,22 +270,24 @@ typedef struct Heartbeat {
 | 
			
		|||
 | 
			
		||||
typedef struct HeartbeatFrag {
 | 
			
		||||
  SubmessageHeader_t smhdr;
 | 
			
		||||
  nn_entityid_t readerId;
 | 
			
		||||
  nn_entityid_t writerId;
 | 
			
		||||
  ddsi_entityid_t readerId;
 | 
			
		||||
  ddsi_entityid_t writerId;
 | 
			
		||||
  nn_sequence_number_t writerSN;
 | 
			
		||||
  nn_fragment_number_t lastFragmentNum;
 | 
			
		||||
  nn_count_t count;
 | 
			
		||||
} HeartbeatFrag_t;
 | 
			
		||||
 | 
			
		||||
DDSRT_WARNING_MSVC_OFF(4200)
 | 
			
		||||
typedef struct NackFrag {
 | 
			
		||||
  SubmessageHeader_t smhdr;
 | 
			
		||||
  nn_entityid_t readerId;
 | 
			
		||||
  nn_entityid_t writerId;
 | 
			
		||||
  ddsi_entityid_t readerId;
 | 
			
		||||
  ddsi_entityid_t writerId;
 | 
			
		||||
  nn_sequence_number_t writerSN;
 | 
			
		||||
  nn_fragment_number_set_header_t fragmentNumberState;
 | 
			
		||||
  uint32_t bits[];
 | 
			
		||||
  /* nn_count_t count; */
 | 
			
		||||
} NackFrag_t;
 | 
			
		||||
DDSRT_WARNING_MSVC_ON(4200)
 | 
			
		||||
#define NACKFRAG_SIZE(numbits) (offsetof (NackFrag_t, bits) + NN_FRAGMENT_NUMBER_SET_BITS_SIZE (numbits) + 4)
 | 
			
		||||
#define NACKFRAG_SIZE_MAX NACKFRAG_SIZE (256u)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -305,12 +312,14 @@ typedef union Submessage {
 | 
			
		|||
  PT_InfoContainer_t pt_infocontainer;
 | 
			
		||||
} Submessage_t;
 | 
			
		||||
 | 
			
		||||
DDSRT_WARNING_MSVC_OFF(4200)
 | 
			
		||||
typedef struct ParticipantMessageData {
 | 
			
		||||
  nn_guid_prefix_t participantGuidPrefix;
 | 
			
		||||
  ddsi_guid_prefix_t participantGuidPrefix;
 | 
			
		||||
  uint32_t kind; /* really 4 octets */
 | 
			
		||||
  uint32_t length;
 | 
			
		||||
  char value[];
 | 
			
		||||
} ParticipantMessageData_t;
 | 
			
		||||
DDSRT_WARNING_MSVC_ON(4200)
 | 
			
		||||
#define PARTICIPANT_MESSAGE_DATA_KIND_UNKNOWN 0x0u
 | 
			
		||||
#define PARTICIPANT_MESSAGE_DATA_KIND_AUTOMATIC_LIVELINESS_UPDATE 0x1u
 | 
			
		||||
#define PARTICIPANT_MESSAGE_DATA_KIND_MANUAL_LIVELINESS_UPDATE 0x2u
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -30,14 +30,14 @@ struct nn_rsample_info;
 | 
			
		|||
struct nn_defrag;
 | 
			
		||||
struct nn_reorder;
 | 
			
		||||
struct nn_dqueue;
 | 
			
		||||
struct nn_guid;
 | 
			
		||||
struct ddsi_guid;
 | 
			
		||||
 | 
			
		||||
struct proxy_writer;
 | 
			
		||||
 | 
			
		||||
struct nn_fragment_number_set;
 | 
			
		||||
struct nn_sequence_number_set;
 | 
			
		||||
 | 
			
		||||
typedef int (*nn_dqueue_handler_t) (const struct nn_rsample_info *sampleinfo, const struct nn_rdata *fragchain, const struct nn_guid *rdguid, void *qarg);
 | 
			
		||||
typedef int (*nn_dqueue_handler_t) (const struct nn_rsample_info *sampleinfo, const struct nn_rdata *fragchain, const struct ddsi_guid *rdguid, void *qarg);
 | 
			
		||||
 | 
			
		||||
struct nn_rmsg_chunk {
 | 
			
		||||
  struct nn_rbuf *rbuf;
 | 
			
		||||
| 
						 | 
				
			
			@ -102,8 +102,8 @@ struct nn_rmsg {
 | 
			
		|||
#define NN_RMSG_PAYLOADOFF(m, o) (NN_RMSG_PAYLOAD (m) + (o))
 | 
			
		||||
 | 
			
		||||
struct receiver_state {
 | 
			
		||||
  nn_guid_prefix_t src_guid_prefix;       /* 12 */
 | 
			
		||||
  nn_guid_prefix_t dst_guid_prefix;       /* 12 */
 | 
			
		||||
  ddsi_guid_prefix_t src_guid_prefix;       /* 12 */
 | 
			
		||||
  ddsi_guid_prefix_t dst_guid_prefix;       /* 12 */
 | 
			
		||||
  struct addrset *reply_locators;         /* 4/8 */
 | 
			
		||||
  int forme;                              /* 4 */
 | 
			
		||||
  nn_vendorid_t vendor;                   /* 2 */
 | 
			
		||||
| 
						 | 
				
			
			@ -234,7 +234,7 @@ void nn_dqueue_free (struct nn_dqueue *q);
 | 
			
		|||
bool nn_dqueue_enqueue_deferred_wakeup (struct nn_dqueue *q, struct nn_rsample_chain *sc, nn_reorder_result_t rres);
 | 
			
		||||
void dd_dqueue_enqueue_trigger (struct nn_dqueue *q);
 | 
			
		||||
void nn_dqueue_enqueue (struct nn_dqueue *q, struct nn_rsample_chain *sc, nn_reorder_result_t rres);
 | 
			
		||||
void nn_dqueue_enqueue1 (struct nn_dqueue *q, const nn_guid_t *rdguid, struct nn_rsample_chain *sc, nn_reorder_result_t rres);
 | 
			
		||||
void nn_dqueue_enqueue1 (struct nn_dqueue *q, const ddsi_guid_t *rdguid, struct nn_rsample_chain *sc, nn_reorder_result_t rres);
 | 
			
		||||
void nn_dqueue_enqueue_callback (struct nn_dqueue *q, nn_dqueue_callback_t cb, void *arg);
 | 
			
		||||
int  nn_dqueue_is_full (struct nn_dqueue *q);
 | 
			
		||||
void nn_dqueue_wait_until_empty_if_full (struct nn_dqueue *q);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -25,7 +25,7 @@ struct recv_thread_arg;
 | 
			
		|||
void trigger_recv_threads (const struct q_globals *gv);
 | 
			
		||||
uint32_t recv_thread (void *vrecv_thread_arg);
 | 
			
		||||
uint32_t listen_thread (struct ddsi_tran_listener * listener);
 | 
			
		||||
int user_dqueue_handler (const struct nn_rsample_info *sampleinfo, const struct nn_rdata *fragchain, const nn_guid_t *rdguid, void *qarg);
 | 
			
		||||
int user_dqueue_handler (const struct nn_rsample_info *sampleinfo, const struct nn_rdata *fragchain, const ddsi_guid_t *rdguid, void *qarg);
 | 
			
		||||
 | 
			
		||||
#if defined (__cplusplus)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,86 +0,0 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
 | 
			
		||||
 *
 | 
			
		||||
 * This program and the accompanying materials are made available under the
 | 
			
		||||
 * terms of the Eclipse Public License v. 2.0 which is available at
 | 
			
		||||
 * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
 | 
			
		||||
 * v. 1.0 which is available at
 | 
			
		||||
 * http://www.eclipse.org/org/documents/edl-v10.php.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
#ifndef Q_RHC_H
 | 
			
		||||
#define Q_RHC_H
 | 
			
		||||
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
 | 
			
		||||
#include "dds/export.h"
 | 
			
		||||
 | 
			
		||||
/* DDS_EXPORT inline i.c.w. __attributes__((visibility...)) and some compilers: */
 | 
			
		||||
#include "dds/ddsrt/attributes.h"
 | 
			
		||||
 | 
			
		||||
#include "dds/ddsi/q_rtps.h"
 | 
			
		||||
 | 
			
		||||
#if defined (__cplusplus)
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
struct dds_qos;
 | 
			
		||||
struct ddsi_tkmap_instance;
 | 
			
		||||
struct ddsi_serdata;
 | 
			
		||||
struct ddsi_sertopic;
 | 
			
		||||
struct entity_common;
 | 
			
		||||
 | 
			
		||||
struct proxy_writer_info
 | 
			
		||||
{
 | 
			
		||||
  nn_guid_t guid;
 | 
			
		||||
  bool auto_dispose;
 | 
			
		||||
  int32_t ownership_strength;
 | 
			
		||||
  uint64_t iid;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct rhc;
 | 
			
		||||
 | 
			
		||||
typedef void (*rhc_free_t) (struct rhc *rhc);
 | 
			
		||||
typedef bool (*rhc_store_t) (struct rhc * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info, struct ddsi_serdata * __restrict sample, struct ddsi_tkmap_instance * __restrict tk);
 | 
			
		||||
typedef void (*rhc_unregister_wr_t) (struct rhc * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info);
 | 
			
		||||
typedef void (*rhc_relinquish_ownership_t) (struct rhc * __restrict rhc, const uint64_t wr_iid);
 | 
			
		||||
typedef void (*rhc_set_qos_t) (struct rhc *rhc, const struct dds_qos *qos);
 | 
			
		||||
 | 
			
		||||
struct rhc_ops {
 | 
			
		||||
  rhc_store_t store;
 | 
			
		||||
  rhc_unregister_wr_t unregister_wr;
 | 
			
		||||
  rhc_relinquish_ownership_t relinquish_ownership;
 | 
			
		||||
  rhc_set_qos_t set_qos;
 | 
			
		||||
  rhc_free_t free;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct rhc {
 | 
			
		||||
  const struct rhc_ops *ops;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
DDS_EXPORT inline bool rhc_store (struct rhc * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info, struct ddsi_serdata * __restrict sample, struct ddsi_tkmap_instance * __restrict tk) {
 | 
			
		||||
  return rhc->ops->store (rhc, pwr_info, sample, tk);
 | 
			
		||||
}
 | 
			
		||||
DDS_EXPORT inline void rhc_unregister_wr (struct rhc * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info) {
 | 
			
		||||
  rhc->ops->unregister_wr (rhc, pwr_info);
 | 
			
		||||
}
 | 
			
		||||
DDS_EXPORT inline void rhc_relinquish_ownership (struct rhc * __restrict rhc, const uint64_t wr_iid) {
 | 
			
		||||
  rhc->ops->relinquish_ownership (rhc, wr_iid);
 | 
			
		||||
}
 | 
			
		||||
DDS_EXPORT inline void rhc_set_qos (struct rhc *rhc, const struct dds_qos *qos) {
 | 
			
		||||
  rhc->ops->set_qos (rhc, qos);
 | 
			
		||||
}
 | 
			
		||||
DDS_EXPORT inline void rhc_free (struct rhc *rhc) {
 | 
			
		||||
  rhc->ops->free (rhc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DDS_EXPORT void make_proxy_writer_info(struct proxy_writer_info *pwr_info, const struct entity_common *e, const struct dds_qos *xqos);
 | 
			
		||||
 | 
			
		||||
#if defined (__cplusplus)
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* Q_RHC_H */
 | 
			
		||||
| 
						 | 
				
			
			@ -13,6 +13,7 @@
 | 
			
		|||
#define NN_RTPS_H
 | 
			
		||||
 | 
			
		||||
#include "dds/ddsi/ddsi_vendor.h"
 | 
			
		||||
#include "dds/ddsi/ddsi_guid.h"
 | 
			
		||||
 | 
			
		||||
#if defined (__cplusplus)
 | 
			
		||||
extern "C" {
 | 
			
		||||
| 
						 | 
				
			
			@ -21,17 +22,6 @@ extern "C" {
 | 
			
		|||
typedef struct {
 | 
			
		||||
  uint8_t major, minor;
 | 
			
		||||
} nn_protocol_version_t;
 | 
			
		||||
typedef union nn_guid_prefix {
 | 
			
		||||
  unsigned char s[12];
 | 
			
		||||
  uint32_t u[3];
 | 
			
		||||
} nn_guid_prefix_t;
 | 
			
		||||
typedef union nn_entityid {
 | 
			
		||||
  uint32_t u;
 | 
			
		||||
} nn_entityid_t;
 | 
			
		||||
typedef struct nn_guid {
 | 
			
		||||
  nn_guid_prefix_t prefix;
 | 
			
		||||
  nn_entityid_t entityid;
 | 
			
		||||
} nn_guid_t;
 | 
			
		||||
typedef int64_t seqno_t;
 | 
			
		||||
#define MAX_SEQ_NUMBER INT64_MAX
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -98,12 +98,9 @@ struct thread_states {
 | 
			
		|||
extern DDS_EXPORT struct thread_states thread_states;
 | 
			
		||||
extern ddsrt_thread_local struct thread_state1 *tsd_thread_state;
 | 
			
		||||
 | 
			
		||||
DDS_EXPORT void thread_states_init_static (void);
 | 
			
		||||
DDS_EXPORT void thread_states_init (unsigned maxthreads);
 | 
			
		||||
DDS_EXPORT void thread_states_fini (void);
 | 
			
		||||
DDS_EXPORT bool thread_states_fini (void);
 | 
			
		||||
 | 
			
		||||
DDS_EXPORT void upgrade_main_thread (void);
 | 
			
		||||
DDS_EXPORT void downgrade_main_thread (void);
 | 
			
		||||
DDS_EXPORT const struct config_thread_properties_listelem *lookup_thread_properties (const struct config *config, const char *name);
 | 
			
		||||
DDS_EXPORT dds_return_t create_thread_with_properties (struct thread_state1 **ts1, struct config_thread_properties_listelem const * const tprops, const char *name, uint32_t (*f) (void *arg), void *arg);
 | 
			
		||||
DDS_EXPORT dds_return_t create_thread (struct thread_state1 **ts, const struct q_globals *gv, const char *name, uint32_t (*f) (void *arg), void *arg);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -42,7 +42,7 @@ int write_sample_nogc_notk (struct thread_state1 * const ts1, struct nn_xpack *x
 | 
			
		|||
/* When calling the following functions, wr->lock must be held */
 | 
			
		||||
dds_return_t create_fragment_message (struct writer *wr, seqno_t seq, const struct nn_plist *plist, struct ddsi_serdata *serdata, unsigned fragnum, struct proxy_reader *prd,struct nn_xmsg **msg, int isnew);
 | 
			
		||||
int enqueue_sample_wrlock_held (struct writer *wr, seqno_t seq, const struct nn_plist *plist, struct ddsi_serdata *serdata, struct proxy_reader *prd, int isnew);
 | 
			
		||||
void add_Heartbeat (struct nn_xmsg *msg, struct writer *wr, const struct whc_state *whcst, int hbansreq, nn_entityid_t dst, int issync);
 | 
			
		||||
void add_Heartbeat (struct nn_xmsg *msg, struct writer *wr, const struct whc_state *whcst, int hbansreq, ddsi_entityid_t dst, int issync);
 | 
			
		||||
 | 
			
		||||
#if defined (__cplusplus)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -46,8 +46,8 @@ DDS_EXPORT dds_return_t xeventq_start (struct xeventq *evq, const char *name); /
 | 
			
		|||
DDS_EXPORT void xeventq_stop (struct xeventq *evq);
 | 
			
		||||
 | 
			
		||||
DDS_EXPORT void qxev_msg (struct xeventq *evq, struct nn_xmsg *msg);
 | 
			
		||||
DDS_EXPORT void qxev_pwr_entityid (struct proxy_writer * pwr, nn_guid_prefix_t * id);
 | 
			
		||||
DDS_EXPORT void qxev_prd_entityid (struct proxy_reader * prd, nn_guid_prefix_t * id);
 | 
			
		||||
DDS_EXPORT void qxev_pwr_entityid (struct proxy_writer * pwr, ddsi_guid_prefix_t * id);
 | 
			
		||||
DDS_EXPORT void qxev_prd_entityid (struct proxy_reader * prd, ddsi_guid_prefix_t * id);
 | 
			
		||||
 | 
			
		||||
/* Returns 1 if queued, 0 otherwise (no point in returning the
 | 
			
		||||
   event, you can't do anything with it anyway) */
 | 
			
		||||
| 
						 | 
				
			
			@ -57,11 +57,11 @@ DDS_EXPORT int qxev_msg_rexmit_wrlock_held (struct xeventq *evq, struct nn_xmsg
 | 
			
		|||
DDS_EXPORT void delete_xevent (struct xevent *ev);
 | 
			
		||||
DDS_EXPORT int resched_xevent_if_earlier (struct xevent *ev, nn_mtime_t tsched);
 | 
			
		||||
 | 
			
		||||
DDS_EXPORT struct xevent *qxev_heartbeat (struct xeventq *evq, nn_mtime_t tsched, const nn_guid_t *wr_guid);
 | 
			
		||||
DDS_EXPORT struct xevent *qxev_acknack (struct xeventq *evq, nn_mtime_t tsched, const nn_guid_t *pwr_guid, const nn_guid_t *rd_guid);
 | 
			
		||||
DDS_EXPORT struct xevent *qxev_spdp (struct xeventq *evq, nn_mtime_t tsched, const nn_guid_t *pp_guid, const nn_guid_t *proxypp_guid);
 | 
			
		||||
DDS_EXPORT struct xevent *qxev_pmd_update (struct xeventq *evq, nn_mtime_t tsched, const nn_guid_t *pp_guid);
 | 
			
		||||
DDS_EXPORT struct xevent *qxev_delete_writer (struct xeventq *evq, nn_mtime_t tsched, const nn_guid_t *guid);
 | 
			
		||||
DDS_EXPORT struct xevent *qxev_heartbeat (struct xeventq *evq, nn_mtime_t tsched, const ddsi_guid_t *wr_guid);
 | 
			
		||||
DDS_EXPORT struct xevent *qxev_acknack (struct xeventq *evq, nn_mtime_t tsched, const ddsi_guid_t *pwr_guid, const ddsi_guid_t *rd_guid);
 | 
			
		||||
DDS_EXPORT struct xevent *qxev_spdp (struct xeventq *evq, nn_mtime_t tsched, const ddsi_guid_t *pp_guid, const ddsi_guid_t *proxypp_guid);
 | 
			
		||||
DDS_EXPORT struct xevent *qxev_pmd_update (struct xeventq *evq, nn_mtime_t tsched, const ddsi_guid_t *pp_guid);
 | 
			
		||||
DDS_EXPORT struct xevent *qxev_delete_writer (struct xeventq *evq, nn_mtime_t tsched, const ddsi_guid_t *guid);
 | 
			
		||||
 | 
			
		||||
/* cb will be called with now = T_NEVER if the event is still enqueued when when xeventq_free starts cleaning up */
 | 
			
		||||
DDS_EXPORT struct xevent *qxev_callback (struct xeventq *evq, nn_mtime_t tsched, void (*cb) (struct xevent *xev, void *arg, nn_mtime_t now), void *arg);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -54,10 +54,10 @@ void nn_xmsgpool_free (struct nn_xmsgpool *pool);
 | 
			
		|||
/* To allocate a new xmsg from the pool; if expected_size is NOT
 | 
			
		||||
   exceeded, no reallocs will be performed, else the address of the
 | 
			
		||||
   xmsg may change because of reallocing when appending to it. */
 | 
			
		||||
struct nn_xmsg *nn_xmsg_new (struct nn_xmsgpool *pool, const nn_guid_prefix_t *src_guid_prefix, size_t expected_size, enum nn_xmsg_kind kind);
 | 
			
		||||
struct nn_xmsg *nn_xmsg_new (struct nn_xmsgpool *pool, const ddsi_guid_prefix_t *src_guid_prefix, size_t expected_size, enum nn_xmsg_kind kind);
 | 
			
		||||
 | 
			
		||||
/* For sending to a particular destination (participant) */
 | 
			
		||||
void nn_xmsg_setdst1 (struct nn_xmsg *m, const nn_guid_prefix_t *gp, const nn_locator_t *addr);
 | 
			
		||||
void nn_xmsg_setdst1 (struct nn_xmsg *m, const ddsi_guid_prefix_t *gp, const nn_locator_t *addr);
 | 
			
		||||
 | 
			
		||||
/* For sending to a particular proxy reader; this is a convenience
 | 
			
		||||
   routine that extracts a suitable address from the proxy reader's
 | 
			
		||||
| 
						 | 
				
			
			@ -80,7 +80,7 @@ int nn_xmsg_setencoderid (struct nn_xmsg *msg, uint32_t encoderid);
 | 
			
		|||
   M must be a rexmit, and for all rexmits this must be called.  It is
 | 
			
		||||
   a separate function because the location may only become known at a
 | 
			
		||||
   late-ish stage in the construction of the message. */
 | 
			
		||||
void nn_xmsg_set_data_readerId (struct nn_xmsg *m, nn_entityid_t *readerId);
 | 
			
		||||
void nn_xmsg_set_data_readerId (struct nn_xmsg *m, ddsi_entityid_t *readerId);
 | 
			
		||||
 | 
			
		||||
/* If M and MADD are both xmsg's containing the same retransmit
 | 
			
		||||
   message, this will merge the destination embedded in MADD into M.
 | 
			
		||||
| 
						 | 
				
			
			@ -97,8 +97,8 @@ int nn_xmsg_merge_rexmit_destinations_wrlock_held (struct q_globals *gv, struct
 | 
			
		|||
/* To set writer ids for updating last transmitted sequence number;
 | 
			
		||||
   wrfragid is 0 based, unlike DDSI but like other places where
 | 
			
		||||
   fragment numbers are handled internally. */
 | 
			
		||||
void nn_xmsg_setwriterseq (struct nn_xmsg *msg, const nn_guid_t *wrguid, seqno_t wrseq);
 | 
			
		||||
void nn_xmsg_setwriterseq_fragid (struct nn_xmsg *msg, const nn_guid_t *wrguid, seqno_t wrseq, nn_fragment_number_t wrfragid);
 | 
			
		||||
void nn_xmsg_setwriterseq (struct nn_xmsg *msg, const ddsi_guid_t *wrguid, seqno_t wrseq);
 | 
			
		||||
void nn_xmsg_setwriterseq_fragid (struct nn_xmsg *msg, const ddsi_guid_t *wrguid, seqno_t wrseq, nn_fragment_number_t wrfragid);
 | 
			
		||||
 | 
			
		||||
/* Comparison function for retransmits: orders messages on writer
 | 
			
		||||
   guid, sequence number and fragment id */
 | 
			
		||||
| 
						 | 
				
			
			@ -109,7 +109,7 @@ size_t nn_xmsg_size (const struct nn_xmsg *m);
 | 
			
		|||
void *nn_xmsg_payload (size_t *sz, struct nn_xmsg *m);
 | 
			
		||||
void nn_xmsg_payload_to_plistsample (struct ddsi_plist_sample *dst, nn_parameterid_t keyparam, const struct nn_xmsg *m);
 | 
			
		||||
enum nn_xmsg_kind nn_xmsg_kind (const struct nn_xmsg *m);
 | 
			
		||||
void nn_xmsg_guid_seq_fragid (const struct nn_xmsg *m, nn_guid_t *wrguid, seqno_t *wrseq, nn_fragment_number_t *wrfragid);
 | 
			
		||||
void nn_xmsg_guid_seq_fragid (const struct nn_xmsg *m, ddsi_guid_t *wrguid, seqno_t *wrseq, nn_fragment_number_t *wrfragid);
 | 
			
		||||
 | 
			
		||||
void *nn_xmsg_submsg_from_marker (struct nn_xmsg *msg, struct nn_xmsg_marker marker);
 | 
			
		||||
void *nn_xmsg_append (struct nn_xmsg *m, struct nn_xmsg_marker *marker, size_t sz);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -32,6 +32,41 @@ typedef ddsi_octetseq_t dds_userdata_qospolicy_t;
 | 
			
		|||
typedef ddsi_octetseq_t dds_topicdata_qospolicy_t;
 | 
			
		||||
typedef ddsi_octetseq_t dds_groupdata_qospolicy_t;
 | 
			
		||||
 | 
			
		||||
typedef struct dds_property {
 | 
			
		||||
  /* The propagate boolean will not be send over the wire.
 | 
			
		||||
   * When the value is 'false', the complete struct shouldn't be send.
 | 
			
		||||
   * It has to be the first variable within the structure because it
 | 
			
		||||
   * is mapped to XbPROP in the serialiser. */
 | 
			
		||||
  unsigned char propagate;
 | 
			
		||||
  char *name;
 | 
			
		||||
  char *value;
 | 
			
		||||
} dds_property_t;
 | 
			
		||||
 | 
			
		||||
typedef struct dds_propertyseq {
 | 
			
		||||
  uint32_t n;
 | 
			
		||||
  dds_property_t *props;
 | 
			
		||||
} dds_propertyseq_t;
 | 
			
		||||
 | 
			
		||||
typedef struct dds_binaryproperty {
 | 
			
		||||
  /* The propagate boolean will not be send over the wire.
 | 
			
		||||
   * When the value is 'false', the complete struct shouldn't be send.
 | 
			
		||||
   * It has to be the first variable within the structure because it
 | 
			
		||||
   * is mapped to XbPROP in the serialiser. */
 | 
			
		||||
  unsigned char propagate;
 | 
			
		||||
  char *name;
 | 
			
		||||
  ddsi_octetseq_t value;
 | 
			
		||||
} dds_binaryproperty_t;
 | 
			
		||||
 | 
			
		||||
typedef struct dds_binarypropertyseq {
 | 
			
		||||
  uint32_t n;
 | 
			
		||||
  dds_binaryproperty_t *props;
 | 
			
		||||
} dds_binarypropertyseq_t;
 | 
			
		||||
 | 
			
		||||
typedef struct dds_property_qospolicy {
 | 
			
		||||
  dds_propertyseq_t value;
 | 
			
		||||
  dds_binarypropertyseq_t binary_value;
 | 
			
		||||
} dds_property_qospolicy_t;
 | 
			
		||||
 | 
			
		||||
typedef struct dds_durability_qospolicy {
 | 
			
		||||
  dds_durability_kind_t kind;
 | 
			
		||||
} dds_durability_qospolicy_t;
 | 
			
		||||
| 
						 | 
				
			
			@ -212,6 +247,7 @@ typedef struct dds_ignorelocal_qospolicy {
 | 
			
		|||
#define QP_PRISMTECH_SUBSCRIPTION_KEYS       ((uint64_t)1 << 25)
 | 
			
		||||
#define QP_PRISMTECH_ENTITY_FACTORY          ((uint64_t)1 << 27)
 | 
			
		||||
#define QP_CYCLONE_IGNORELOCAL               ((uint64_t)1 << 30)
 | 
			
		||||
#define QP_PROPERTY_LIST                     ((uint64_t)1 << 31)
 | 
			
		||||
 | 
			
		||||
/* Partition QoS is not RxO according to the specification (DDS 1.2,
 | 
			
		||||
   section 7.1.3), but communication will not take place unless it
 | 
			
		||||
| 
						 | 
				
			
			@ -263,6 +299,7 @@ struct dds_qos {
 | 
			
		|||
  /*x xR*/dds_subscription_keys_qospolicy_t subscription_keys;
 | 
			
		||||
  /*x xR*/dds_reader_lifespan_qospolicy_t reader_lifespan;
 | 
			
		||||
  /* x  */dds_ignorelocal_qospolicy_t ignorelocal;
 | 
			
		||||
  /*xxx */dds_property_qospolicy_t property;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct nn_xmsg;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -211,7 +211,12 @@ static ddsi_tran_conn_t ddsi_raweth_create_conn (ddsi_tran_factory_t fact, uint3
 | 
			
		|||
    return NULL;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  uc = (ddsi_raweth_conn_t) ddsrt_malloc (sizeof (*uc));
 | 
			
		||||
  if ((uc = (ddsi_raweth_conn_t) ddsrt_malloc (sizeof (*uc))) == NULL)
 | 
			
		||||
  {
 | 
			
		||||
    ddsrt_close(sock);
 | 
			
		||||
    return NULL;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  memset (uc, 0, sizeof (*uc));
 | 
			
		||||
  uc->m_sock = sock;
 | 
			
		||||
  uc->m_ifindex = addr.sll_ifindex;
 | 
			
		||||
| 
						 | 
				
			
			@ -226,7 +231,7 @@ static ddsi_tran_conn_t ddsi_raweth_create_conn (ddsi_tran_factory_t fact, uint3
 | 
			
		|||
  uc->m_base.m_disable_multiplexing_fn = 0;
 | 
			
		||||
 | 
			
		||||
  DDS_CTRACE (&fact->gv->logconfig, "ddsi_raweth_create_conn %s socket %d port %u\n", mcast ? "multicast" : "unicast", uc->m_sock, uc->m_base.m_base.m_port);
 | 
			
		||||
  return uc ? &uc->m_base : NULL;
 | 
			
		||||
  return &uc->m_base;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int isbroadcast(const nn_locator_t *loc)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										18
									
								
								src/core/ddsi/src/ddsi_rhc.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/core/ddsi/src/ddsi_rhc.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,18 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
 | 
			
		||||
 *
 | 
			
		||||
 * This program and the accompanying materials are made available under the
 | 
			
		||||
 * terms of the Eclipse Public License v. 2.0 which is available at
 | 
			
		||||
 * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
 | 
			
		||||
 * v. 1.0 which is available at
 | 
			
		||||
 * http://www.eclipse.org/org/documents/edl-v10.php.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
#include "dds/ddsi/ddsi_rhc.h"
 | 
			
		||||
 | 
			
		||||
extern inline void ddsi_rhc_free (struct ddsi_rhc *rhc);
 | 
			
		||||
extern inline bool ddsi_rhc_store (struct ddsi_rhc * __restrict rhc, const struct ddsi_writer_info * __restrict wrinfo, struct ddsi_serdata * __restrict sample, struct ddsi_tkmap_instance * __restrict tk);
 | 
			
		||||
extern inline void ddsi_rhc_unregister_wr (struct ddsi_rhc * __restrict rhc, const struct ddsi_writer_info * __restrict wrinfo);
 | 
			
		||||
extern inline void ddsi_rhc_relinquish_ownership (struct ddsi_rhc * __restrict rhc, const uint64_t wr_iid);
 | 
			
		||||
extern inline void ddsi_rhc_set_qos (struct ddsi_rhc *rhc, const struct dds_qos *qos);
 | 
			
		||||
| 
						 | 
				
			
			@ -45,3 +45,5 @@ extern inline void ddsi_serdata_to_ser_unref (struct ddsi_serdata *d, const ddsr
 | 
			
		|||
extern inline bool ddsi_serdata_to_sample (const struct ddsi_serdata *d, void *sample, void **bufptr, void *buflim);
 | 
			
		||||
extern inline bool ddsi_serdata_topicless_to_sample (const struct ddsi_sertopic *topic, const struct ddsi_serdata *d, void *sample, void **bufptr, void *buflim);
 | 
			
		||||
extern inline bool ddsi_serdata_eqkey (const struct ddsi_serdata *a, const struct ddsi_serdata *b);
 | 
			
		||||
extern inline bool ddsi_serdata_print (const struct ddsi_serdata *d, char *buf, size_t size);
 | 
			
		||||
extern inline bool ddsi_serdata_print_topicless (const struct ddsi_sertopic *topic, const struct ddsi_serdata *d, char *buf, size_t size);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -453,6 +453,7 @@ static struct ddsi_serdata *serdata_default_from_sample_plist (const struct ddsi
 | 
			
		|||
#ifndef NDEBUG
 | 
			
		||||
  size_t keysize;
 | 
			
		||||
#endif
 | 
			
		||||
  assert(rawkey);
 | 
			
		||||
  switch (sample->keyparam)
 | 
			
		||||
  {
 | 
			
		||||
    case PID_PARTICIPANT_GUID:
 | 
			
		||||
| 
						 | 
				
			
			@ -629,6 +630,32 @@ static bool serdata_default_topicless_to_sample_cdr_nokey (const struct ddsi_ser
 | 
			
		|||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static size_t serdata_default_print_cdr (const struct ddsi_sertopic *sertopic_common, const struct ddsi_serdata *serdata_common, char *buf, size_t size)
 | 
			
		||||
{
 | 
			
		||||
  const struct ddsi_serdata_default *d = (const struct ddsi_serdata_default *)serdata_common;
 | 
			
		||||
  const struct ddsi_sertopic_default *tp = (const struct ddsi_sertopic_default *)sertopic_common;
 | 
			
		||||
  dds_istream_t is;
 | 
			
		||||
  dds_istream_from_serdata_default (&is, d);
 | 
			
		||||
  if (d->c.kind == SDK_KEY)
 | 
			
		||||
    return dds_stream_print_key (&is, tp, buf, size);
 | 
			
		||||
  else
 | 
			
		||||
    return dds_stream_print_sample (&is, tp, buf, size);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static size_t serdata_default_print_plist (const struct ddsi_sertopic *sertopic_common, const struct ddsi_serdata *serdata_common, char *buf, size_t size)
 | 
			
		||||
{
 | 
			
		||||
  /* FIXME: should change q_plist.c to print to a string instead of a log, and then drop the
 | 
			
		||||
     logging of QoS in the rest of code, instead relying on this */
 | 
			
		||||
  (void)sertopic_common; (void)serdata_common;
 | 
			
		||||
  return (size_t) snprintf (buf, size, "(plist)");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static size_t serdata_default_print_raw (const struct ddsi_sertopic *sertopic_common, const struct ddsi_serdata *serdata_common, char *buf, size_t size)
 | 
			
		||||
{
 | 
			
		||||
  (void)sertopic_common; (void)serdata_common;
 | 
			
		||||
  return (size_t) snprintf (buf, size, "(blob)");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const struct ddsi_serdata_ops ddsi_serdata_ops_cdr = {
 | 
			
		||||
  .get_size = serdata_default_get_size,
 | 
			
		||||
  .eqkey = serdata_default_eqkey,
 | 
			
		||||
| 
						 | 
				
			
			@ -641,7 +668,8 @@ const struct ddsi_serdata_ops ddsi_serdata_ops_cdr = {
 | 
			
		|||
  .to_ser_ref = serdata_default_to_ser_ref,
 | 
			
		||||
  .to_ser_unref = serdata_default_to_ser_unref,
 | 
			
		||||
  .to_topicless = serdata_default_to_topicless,
 | 
			
		||||
  .topicless_to_sample = serdata_default_topicless_to_sample_cdr
 | 
			
		||||
  .topicless_to_sample = serdata_default_topicless_to_sample_cdr,
 | 
			
		||||
  .print = serdata_default_print_cdr
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const struct ddsi_serdata_ops ddsi_serdata_ops_cdr_nokey = {
 | 
			
		||||
| 
						 | 
				
			
			@ -656,7 +684,8 @@ const struct ddsi_serdata_ops ddsi_serdata_ops_cdr_nokey = {
 | 
			
		|||
  .to_ser_ref = serdata_default_to_ser_ref,
 | 
			
		||||
  .to_ser_unref = serdata_default_to_ser_unref,
 | 
			
		||||
  .to_topicless = serdata_default_to_topicless,
 | 
			
		||||
  .topicless_to_sample = serdata_default_topicless_to_sample_cdr_nokey
 | 
			
		||||
  .topicless_to_sample = serdata_default_topicless_to_sample_cdr_nokey,
 | 
			
		||||
  .print = serdata_default_print_cdr
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const struct ddsi_serdata_ops ddsi_serdata_ops_plist = {
 | 
			
		||||
| 
						 | 
				
			
			@ -671,7 +700,8 @@ const struct ddsi_serdata_ops ddsi_serdata_ops_plist = {
 | 
			
		|||
  .to_ser_ref = serdata_default_to_ser_ref,
 | 
			
		||||
  .to_ser_unref = serdata_default_to_ser_unref,
 | 
			
		||||
  .to_topicless = serdata_default_to_topicless,
 | 
			
		||||
  .topicless_to_sample = 0
 | 
			
		||||
  .topicless_to_sample = 0,
 | 
			
		||||
  .print = serdata_default_print_plist
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const struct ddsi_serdata_ops ddsi_serdata_ops_rawcdr = {
 | 
			
		||||
| 
						 | 
				
			
			@ -686,5 +716,6 @@ const struct ddsi_serdata_ops ddsi_serdata_ops_rawcdr = {
 | 
			
		|||
  .to_ser_ref = serdata_default_to_ser_ref,
 | 
			
		||||
  .to_ser_unref = serdata_default_to_ser_unref,
 | 
			
		||||
  .to_topicless = serdata_default_to_topicless,
 | 
			
		||||
  .topicless_to_sample = 0
 | 
			
		||||
  .topicless_to_sample = 0,
 | 
			
		||||
  .print = serdata_default_print_raw
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -554,8 +554,9 @@ static ssize_t ddsi_tcp_conn_write (ddsi_tran_conn_t base, const nn_locator_t *d
 | 
			
		|||
 | 
			
		||||
  /* If not connected attempt to conect */
 | 
			
		||||
 | 
			
		||||
  if ((conn->m_sock == DDSRT_INVALID_SOCKET) && ! conn->m_base.m_server)
 | 
			
		||||
  if (conn->m_sock == DDSRT_INVALID_SOCKET)
 | 
			
		||||
  {
 | 
			
		||||
    assert (!conn->m_base.m_server);
 | 
			
		||||
    ddsi_tcp_conn_connect (conn, &msg);
 | 
			
		||||
    if (conn->m_sock == DDSRT_INVALID_SOCKET)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -265,7 +265,7 @@ void ddsi_threadmon_unregister_domain (struct ddsi_threadmon *sl, const struct q
 | 
			
		|||
    dummy.gv = gv;
 | 
			
		||||
    struct threadmon_domain *tmdom = ddsrt_hh_lookup (sl->domains, &dummy);
 | 
			
		||||
    assert (tmdom);
 | 
			
		||||
    ddsrt_hh_remove (sl->domains, tmdom);
 | 
			
		||||
    (void) ddsrt_hh_remove (sl->domains, tmdom);
 | 
			
		||||
    ddsrt_mutex_unlock (&sl->lock);
 | 
			
		||||
    ddsrt_free (tmdom);
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,7 +11,7 @@
 | 
			
		|||
 */
 | 
			
		||||
#include "dds/ddsi/q_bswap.h"
 | 
			
		||||
 | 
			
		||||
nn_guid_prefix_t nn_hton_guid_prefix (nn_guid_prefix_t p)
 | 
			
		||||
ddsi_guid_prefix_t nn_hton_guid_prefix (ddsi_guid_prefix_t p)
 | 
			
		||||
{
 | 
			
		||||
  int i;
 | 
			
		||||
  for (i = 0; i < 3; i++)
 | 
			
		||||
| 
						 | 
				
			
			@ -19,7 +19,7 @@ nn_guid_prefix_t nn_hton_guid_prefix (nn_guid_prefix_t p)
 | 
			
		|||
  return p;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
nn_guid_prefix_t nn_ntoh_guid_prefix (nn_guid_prefix_t p)
 | 
			
		||||
ddsi_guid_prefix_t nn_ntoh_guid_prefix (ddsi_guid_prefix_t p)
 | 
			
		||||
{
 | 
			
		||||
  int i;
 | 
			
		||||
  for (i = 0; i < 3; i++)
 | 
			
		||||
| 
						 | 
				
			
			@ -27,26 +27,26 @@ nn_guid_prefix_t nn_ntoh_guid_prefix (nn_guid_prefix_t p)
 | 
			
		|||
  return p;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
nn_entityid_t nn_hton_entityid (nn_entityid_t e)
 | 
			
		||||
ddsi_entityid_t nn_hton_entityid (ddsi_entityid_t e)
 | 
			
		||||
{
 | 
			
		||||
  e.u = toBE4u (e.u);
 | 
			
		||||
  return e;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
nn_entityid_t nn_ntoh_entityid (nn_entityid_t e)
 | 
			
		||||
ddsi_entityid_t nn_ntoh_entityid (ddsi_entityid_t e)
 | 
			
		||||
{
 | 
			
		||||
  e.u = fromBE4u (e.u);
 | 
			
		||||
  return e;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
nn_guid_t nn_hton_guid (nn_guid_t g)
 | 
			
		||||
ddsi_guid_t nn_hton_guid (ddsi_guid_t g)
 | 
			
		||||
{
 | 
			
		||||
  g.prefix = nn_hton_guid_prefix (g.prefix);
 | 
			
		||||
  g.entityid = nn_hton_entityid (g.entityid);
 | 
			
		||||
  return g;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
nn_guid_t nn_ntoh_guid (nn_guid_t g)
 | 
			
		||||
ddsi_guid_t nn_ntoh_guid (ddsi_guid_t g)
 | 
			
		||||
{
 | 
			
		||||
  g.prefix = nn_ntoh_guid_prefix (g.prefix);
 | 
			
		||||
  g.entityid = nn_ntoh_entityid (g.entityid);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1012,6 +1012,8 @@ static size_t cfg_note_vsnprintf (struct cfg_note_buf *bb, const char *fmt, va_l
 | 
			
		|||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void cfg_note_snprintf (struct cfg_note_buf *bb, const char *fmt, ...) ddsrt_attribute_format ((printf, 2, 3));
 | 
			
		||||
 | 
			
		||||
static void cfg_note_snprintf (struct cfg_note_buf *bb, const char *fmt, ...)
 | 
			
		||||
{
 | 
			
		||||
  /* The reason the 2nd call to os_vsnprintf is here and not inside
 | 
			
		||||
| 
						 | 
				
			
			@ -1123,6 +1125,8 @@ static size_t cfg_note (struct cfgst *cfgst, uint32_t cat, size_t bsz, const cha
 | 
			
		|||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void cfg_warning (struct cfgst *cfgst, const char *fmt, ...) ddsrt_attribute_format ((printf, 2, 3));
 | 
			
		||||
 | 
			
		||||
static void cfg_warning (struct cfgst *cfgst, const char *fmt, ...)
 | 
			
		||||
{
 | 
			
		||||
  va_list ap;
 | 
			
		||||
| 
						 | 
				
			
			@ -1134,6 +1138,8 @@ static void cfg_warning (struct cfgst *cfgst, const char *fmt, ...)
 | 
			
		|||
  } while (bsz > 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static enum update_result cfg_error (struct cfgst *cfgst, const char *fmt, ...) ddsrt_attribute_format ((printf, 2, 3));
 | 
			
		||||
 | 
			
		||||
static enum update_result cfg_error (struct cfgst *cfgst, const char *fmt, ...)
 | 
			
		||||
{
 | 
			
		||||
  va_list ap;
 | 
			
		||||
| 
						 | 
				
			
			@ -1146,6 +1152,8 @@ static enum update_result cfg_error (struct cfgst *cfgst, const char *fmt, ...)
 | 
			
		|||
  return URES_ERROR;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void cfg_logelem (struct cfgst *cfgst, uint32_t sources, const char *fmt, ...) ddsrt_attribute_format ((printf, 3, 4));
 | 
			
		||||
 | 
			
		||||
static void cfg_logelem (struct cfgst *cfgst, uint32_t sources, const char *fmt, ...)
 | 
			
		||||
{
 | 
			
		||||
  /* 89 = 1 + 2 + 31 + 1 + 10 + 2*22: the number of characters in
 | 
			
		||||
| 
						 | 
				
			
			@ -1317,14 +1325,17 @@ static enum update_result do_uint32_bitset (struct cfgst *cfgst, uint32_t *cats,
 | 
			
		|||
  char *copy = ddsrt_strdup (value), *cursor = copy, *tok;
 | 
			
		||||
  while ((tok = ddsrt_strsep (&cursor, ",")) != NULL)
 | 
			
		||||
  {
 | 
			
		||||
    const int idx = list_index (names, tok);
 | 
			
		||||
    const int idx = list_index (names, tok[0] == '-' ? tok+1 : tok);
 | 
			
		||||
    if (idx < 0)
 | 
			
		||||
    {
 | 
			
		||||
      const enum update_result ret = cfg_error (cfgst, "'%s' in '%s' undefined", tok, value);
 | 
			
		||||
      ddsrt_free (copy);
 | 
			
		||||
      return ret;
 | 
			
		||||
    }
 | 
			
		||||
    *cats |= codes[idx];
 | 
			
		||||
    if (tok[0] == '-')
 | 
			
		||||
      *cats &= ~codes[idx];
 | 
			
		||||
    else
 | 
			
		||||
      *cats |= codes[idx];
 | 
			
		||||
  }
 | 
			
		||||
  ddsrt_free (copy);
 | 
			
		||||
  return URES_SUCCESS;
 | 
			
		||||
| 
						 | 
				
			
			@ -1441,7 +1452,7 @@ static void pf_int64_unit (struct cfgst *cfgst, int64_t value, uint32_t sources,
 | 
			
		|||
    }
 | 
			
		||||
    assert (m > 0);
 | 
			
		||||
    assert (unit != NULL);
 | 
			
		||||
    cfg_logelem (cfgst, sources, "%lld %s", value / m, unit);
 | 
			
		||||
    cfg_logelem (cfgst, sources, "%"PRId64" %s", value / m, unit);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1517,10 +1528,10 @@ GENERIC_ENUM_CTYPE (standards_conformance, enum nn_standards_conformance)
 | 
			
		|||
 | 
			
		||||
/* "trace" is special: it enables (nearly) everything */
 | 
			
		||||
static const char *tracemask_names[] = {
 | 
			
		||||
  "fatal", "error", "warning", "info", "config", "discovery", "data", "radmin", "timing", "traffic", "topic", "tcp", "plist", "whc", "throttle", "rhc", "trace", NULL
 | 
			
		||||
  "fatal", "error", "warning", "info", "config", "discovery", "data", "radmin", "timing", "traffic", "topic", "tcp", "plist", "whc", "throttle", "rhc", "content", "trace", NULL
 | 
			
		||||
};
 | 
			
		||||
static const uint32_t tracemask_codes[] = {
 | 
			
		||||
  DDS_LC_FATAL, DDS_LC_ERROR, DDS_LC_WARNING, DDS_LC_INFO, DDS_LC_CONFIG, DDS_LC_DISCOVERY, DDS_LC_DATA, DDS_LC_RADMIN, DDS_LC_TIMING, DDS_LC_TRAFFIC, DDS_LC_TOPIC, DDS_LC_TCP, DDS_LC_PLIST, DDS_LC_WHC, DDS_LC_THROTTLE, DDS_LC_RHC, DDS_LC_ALL
 | 
			
		||||
  DDS_LC_FATAL, DDS_LC_ERROR, DDS_LC_WARNING, DDS_LC_INFO, DDS_LC_CONFIG, DDS_LC_DISCOVERY, DDS_LC_DATA, DDS_LC_RADMIN, DDS_LC_TIMING, DDS_LC_TRAFFIC, DDS_LC_TOPIC, DDS_LC_TCP, DDS_LC_PLIST, DDS_LC_WHC, DDS_LC_THROTTLE, DDS_LC_RHC, DDS_LC_CONTENT, DDS_LC_ALL
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static enum update_result uf_tracemask (struct cfgst *cfgst, UNUSED_ARG (void *parent), UNUSED_ARG (struct cfgelem const * const cfgelem), UNUSED_ARG (int first), const char *value)
 | 
			
		||||
| 
						 | 
				
			
			@ -2383,6 +2394,8 @@ static int proc_elem_open (void *varg, UNUSED_ARG (uintptr_t parentinfo), UNUSED
 | 
			
		|||
        cfgst_push (cfgst, 0, &root_cfgelems[0], cfgst_parent (cfgst));
 | 
			
		||||
        cfgst->implicit_toplevel = ITL_INSERTED_2;
 | 
			
		||||
      }
 | 
			
		||||
      cfgst->source = (cfgst->source == 0) ? 1 : cfgst->source << 1;
 | 
			
		||||
      cfgst->first_data_in_source = true;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2691,10 +2704,13 @@ static FILE *config_open_file (char *tok, char **cursor, uint32_t domid)
 | 
			
		|||
  return fp;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct cfgst *config_init (const char *configfile, struct config *cfg, uint32_t domid)
 | 
			
		||||
struct cfgst *config_init (const char *config, struct config *cfg, uint32_t domid)
 | 
			
		||||
{
 | 
			
		||||
  int ok = 1;
 | 
			
		||||
  struct cfgst *cfgst;
 | 
			
		||||
  char env_input[32];
 | 
			
		||||
  char *copy, *cursor;
 | 
			
		||||
  struct ddsrt_xmlp_callbacks cb;
 | 
			
		||||
 | 
			
		||||
  memset (cfg, 0, sizeof (*cfg));
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2715,72 +2731,67 @@ struct cfgst *config_init (const char *configfile, struct config *cfg, uint32_t
 | 
			
		|||
     ends up on the right value */
 | 
			
		||||
  cfgst->cfg->domainId = domid;
 | 
			
		||||
 | 
			
		||||
  /* configfile == NULL will get you the default configuration */
 | 
			
		||||
  if (configfile) {
 | 
			
		||||
    char env_input[32];
 | 
			
		||||
    char *copy = ddsrt_strdup (configfile), *cursor = copy;
 | 
			
		||||
    struct ddsrt_xmlp_callbacks cb;
 | 
			
		||||
  cb.attr = proc_attr;
 | 
			
		||||
  cb.elem_close = proc_elem_close;
 | 
			
		||||
  cb.elem_data = proc_elem_data;
 | 
			
		||||
  cb.elem_open = proc_elem_open;
 | 
			
		||||
  cb.error = proc_error;
 | 
			
		||||
 | 
			
		||||
    cb.attr = proc_attr;
 | 
			
		||||
    cb.elem_close = proc_elem_close;
 | 
			
		||||
    cb.elem_data = proc_elem_data;
 | 
			
		||||
    cb.elem_open = proc_elem_open;
 | 
			
		||||
    cb.error = proc_error;
 | 
			
		||||
 | 
			
		||||
    while (*cursor && (isspace ((unsigned char) *cursor) || *cursor == ','))
 | 
			
		||||
      cursor++;
 | 
			
		||||
    while (ok && cursor && cursor[0])
 | 
			
		||||
  copy = ddsrt_strdup (config);
 | 
			
		||||
  cursor = copy;
 | 
			
		||||
  while (*cursor && (isspace ((unsigned char) *cursor) || *cursor == ','))
 | 
			
		||||
    cursor++;
 | 
			
		||||
  while (ok && cursor && cursor[0])
 | 
			
		||||
  {
 | 
			
		||||
    struct ddsrt_xmlp_state *qx;
 | 
			
		||||
    FILE *fp;
 | 
			
		||||
    char *tok;
 | 
			
		||||
    tok = cursor;
 | 
			
		||||
    if (tok[0] == '<')
 | 
			
		||||
    {
 | 
			
		||||
      struct ddsrt_xmlp_state *qx;
 | 
			
		||||
      FILE *fp;
 | 
			
		||||
      char *tok;
 | 
			
		||||
      tok = cursor;
 | 
			
		||||
      if (tok[0] == '<')
 | 
			
		||||
      {
 | 
			
		||||
        /* Read XML directly from input string */
 | 
			
		||||
        qx = ddsrt_xmlp_new_string (tok, cfgst, &cb);
 | 
			
		||||
        ddsrt_xmlp_set_options (qx, DDSRT_XMLP_ANONYMOUS_CLOSE_TAG | DDSRT_XMLP_MISSING_CLOSE_AS_EOF);
 | 
			
		||||
        fp = NULL;
 | 
			
		||||
        snprintf (env_input, sizeof (env_input), "CYCLONEDDS_URI+%u", (unsigned) (tok - copy));
 | 
			
		||||
        cfgst->input = env_input;
 | 
			
		||||
        cfgst->line = 1;
 | 
			
		||||
      }
 | 
			
		||||
      else if ((fp = config_open_file (tok, &cursor, domid)) == NULL)
 | 
			
		||||
      {
 | 
			
		||||
        ddsrt_free (copy);
 | 
			
		||||
        goto error;
 | 
			
		||||
      }
 | 
			
		||||
      else
 | 
			
		||||
      {
 | 
			
		||||
        qx = ddsrt_xmlp_new_file (fp, cfgst, &cb);
 | 
			
		||||
        cfgst->input = tok;
 | 
			
		||||
        cfgst->line = 1;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      cfgst->implicit_toplevel = (fp == NULL) ? ITL_ALLOWED : ITL_DISALLOWED;
 | 
			
		||||
      cfgst->first_data_in_source = true;
 | 
			
		||||
      cfgst_push (cfgst, 0, &root_cfgelem, cfgst->cfg);
 | 
			
		||||
      ok = (ddsrt_xmlp_parse (qx) >= 0) && !cfgst->error;
 | 
			
		||||
      assert (!ok ||
 | 
			
		||||
              (cfgst->path_depth == 1 && cfgst->implicit_toplevel == ITL_DISALLOWED) ||
 | 
			
		||||
              (cfgst->path_depth == 1 + (int) cfgst->implicit_toplevel));
 | 
			
		||||
      /* Pop until stack empty: error handling is rather brutal */
 | 
			
		||||
      while (cfgst->path_depth > 0)
 | 
			
		||||
        cfgst_pop (cfgst);
 | 
			
		||||
      if (fp != NULL)
 | 
			
		||||
        fclose (fp);
 | 
			
		||||
      else if (ok)
 | 
			
		||||
        cursor = tok + ddsrt_xmlp_get_bufpos (qx);
 | 
			
		||||
      ddsrt_xmlp_free (qx);
 | 
			
		||||
      assert (fp == NULL || cfgst->implicit_toplevel <= ITL_ALLOWED);
 | 
			
		||||
      if (cursor)
 | 
			
		||||
      {
 | 
			
		||||
        while (*cursor && (isspace ((unsigned char) cursor[0]) || cursor[0] == ','))
 | 
			
		||||
          cursor++;
 | 
			
		||||
      }
 | 
			
		||||
      /* Read XML directly from input string */
 | 
			
		||||
      qx = ddsrt_xmlp_new_string (tok, cfgst, &cb);
 | 
			
		||||
      ddsrt_xmlp_set_options (qx, DDSRT_XMLP_ANONYMOUS_CLOSE_TAG | DDSRT_XMLP_MISSING_CLOSE_AS_EOF);
 | 
			
		||||
      fp = NULL;
 | 
			
		||||
      snprintf (env_input, sizeof (env_input), "CYCLONEDDS_URI+%u", (unsigned) (tok - copy));
 | 
			
		||||
      cfgst->input = env_input;
 | 
			
		||||
      cfgst->line = 1;
 | 
			
		||||
    }
 | 
			
		||||
    else if ((fp = config_open_file (tok, &cursor, domid)) == NULL)
 | 
			
		||||
    {
 | 
			
		||||
      ddsrt_free (copy);
 | 
			
		||||
      goto error;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
      qx = ddsrt_xmlp_new_file (fp, cfgst, &cb);
 | 
			
		||||
      cfgst->input = tok;
 | 
			
		||||
      cfgst->line = 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    cfgst->implicit_toplevel = (fp == NULL) ? ITL_ALLOWED : ITL_DISALLOWED;
 | 
			
		||||
    cfgst->first_data_in_source = true;
 | 
			
		||||
    cfgst_push (cfgst, 0, &root_cfgelem, cfgst->cfg);
 | 
			
		||||
    ok = (ddsrt_xmlp_parse (qx) >= 0) && !cfgst->error;
 | 
			
		||||
    assert (!ok ||
 | 
			
		||||
            (cfgst->path_depth == 1 && cfgst->implicit_toplevel == ITL_DISALLOWED) ||
 | 
			
		||||
            (cfgst->path_depth == 1 + (int) cfgst->implicit_toplevel));
 | 
			
		||||
    /* Pop until stack empty: error handling is rather brutal */
 | 
			
		||||
    while (cfgst->path_depth > 0)
 | 
			
		||||
      cfgst_pop (cfgst);
 | 
			
		||||
    if (fp != NULL)
 | 
			
		||||
      fclose (fp);
 | 
			
		||||
    else if (ok)
 | 
			
		||||
      cursor = tok + ddsrt_xmlp_get_bufpos (qx);
 | 
			
		||||
    ddsrt_xmlp_free (qx);
 | 
			
		||||
    assert (fp == NULL || cfgst->implicit_toplevel <= ITL_ALLOWED);
 | 
			
		||||
    if (cursor)
 | 
			
		||||
    {
 | 
			
		||||
      while (*cursor && (isspace ((unsigned char) cursor[0]) || cursor[0] == ','))
 | 
			
		||||
        cursor++;
 | 
			
		||||
    }
 | 
			
		||||
    ddsrt_free (copy);
 | 
			
		||||
  }
 | 
			
		||||
  ddsrt_free (copy);
 | 
			
		||||
 | 
			
		||||
  /* Set defaults for everything not set that we have a default value
 | 
			
		||||
     for, signal errors for things unset but without a default. */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,6 +21,7 @@
 | 
			
		|||
#include "dds/ddsrt/md5.h"
 | 
			
		||||
#include "dds/ddsrt/sync.h"
 | 
			
		||||
#include "dds/ddsrt/avl.h"
 | 
			
		||||
#include "dds/ddsrt/string.h"
 | 
			
		||||
#include "dds/ddsi/q_protocol.h"
 | 
			
		||||
#include "dds/ddsi/q_rtps.h"
 | 
			
		||||
#include "dds/ddsi/q_misc.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -302,8 +303,8 @@ int spdp_write (struct participant *pp)
 | 
			
		|||
      ps.prismtech_participant_version_info.flags |= NN_PRISMTECH_FL_PARTICIPANT_IS_DDSI2;
 | 
			
		||||
    ddsrt_mutex_unlock (&pp->e.gv->privileged_pp_lock);
 | 
			
		||||
 | 
			
		||||
    ddsrt_gethostname(node, sizeof(node)-1);
 | 
			
		||||
    node[sizeof(node)-1] = '\0';
 | 
			
		||||
    if (ddsrt_gethostname(node, sizeof(node)-1) < 0)
 | 
			
		||||
      ddsrt_strlcpy (node, "unknown", sizeof (node));
 | 
			
		||||
    size = strlen(node) + strlen(DDS_VERSION) + strlen(DDS_HOST_NAME) + strlen(DDS_TARGET_NAME) + 4; /* + ///'\0' */
 | 
			
		||||
    ps.prismtech_participant_version_info.internals = ddsrt_malloc(size);
 | 
			
		||||
    (void) snprintf(ps.prismtech_participant_version_info.internals, size, "%s/%s/%s/%s", node, DDS_VERSION, DDS_HOST_NAME, DDS_TARGET_NAME);
 | 
			
		||||
| 
						 | 
				
			
			@ -352,7 +353,7 @@ int spdp_dispose_unregister (struct participant *pp)
 | 
			
		|||
  return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static unsigned pseudo_random_delay (const nn_guid_t *x, const nn_guid_t *y, nn_mtime_t tnow)
 | 
			
		||||
static unsigned pseudo_random_delay (const ddsi_guid_t *x, const ddsi_guid_t *y, nn_mtime_t tnow)
 | 
			
		||||
{
 | 
			
		||||
  /* You know, an ordinary random generator would be even better, but
 | 
			
		||||
     the C library doesn't have a reentrant one and I don't feel like
 | 
			
		||||
| 
						 | 
				
			
			@ -381,7 +382,7 @@ static unsigned pseudo_random_delay (const nn_guid_t *x, const nn_guid_t *y, nn_
 | 
			
		|||
  return (unsigned) (m >> 32);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void respond_to_spdp (const struct q_globals *gv, const nn_guid_t *dest_proxypp_guid)
 | 
			
		||||
static void respond_to_spdp (const struct q_globals *gv, const ddsi_guid_t *dest_proxypp_guid)
 | 
			
		||||
{
 | 
			
		||||
  struct ephash_enum_participant est;
 | 
			
		||||
  struct participant *pp;
 | 
			
		||||
| 
						 | 
				
			
			@ -409,10 +410,9 @@ static void respond_to_spdp (const struct q_globals *gv, const nn_guid_t *dest_p
 | 
			
		|||
static int handle_SPDP_dead (const struct receiver_state *rst, nn_wctime_t timestamp, const nn_plist_t *datap, unsigned statusinfo)
 | 
			
		||||
{
 | 
			
		||||
  struct q_globals * const gv = rst->gv;
 | 
			
		||||
  nn_guid_t guid;
 | 
			
		||||
  ddsi_guid_t guid;
 | 
			
		||||
 | 
			
		||||
  if (!(gv->logconfig.c.mask & DDS_LC_DISCOVERY))
 | 
			
		||||
    GVLOGDISC ("SPDP ST%x", statusinfo);
 | 
			
		||||
  GVLOGDISC ("SPDP ST%x", statusinfo);
 | 
			
		||||
 | 
			
		||||
  if (datap->present & PP_PARTICIPANT_GUID)
 | 
			
		||||
  {
 | 
			
		||||
| 
						 | 
				
			
			@ -455,7 +455,7 @@ static void allowmulticast_aware_add_to_addrset (const struct q_globals *gv, uin
 | 
			
		|||
  add_to_addrset (gv, as, loc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct proxy_participant *find_ddsi2_proxy_participant (const struct ephash *guid_hash, const nn_guid_t *ppguid)
 | 
			
		||||
static struct proxy_participant *find_ddsi2_proxy_participant (const struct ephash *guid_hash, const ddsi_guid_t *ppguid)
 | 
			
		||||
{
 | 
			
		||||
  struct ephash_enum_proxy_participant it;
 | 
			
		||||
  struct proxy_participant *pp;
 | 
			
		||||
| 
						 | 
				
			
			@ -469,7 +469,7 @@ static struct proxy_participant *find_ddsi2_proxy_participant (const struct epha
 | 
			
		|||
  return pp;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void make_participants_dependent_on_ddsi2 (struct q_globals *gv, const nn_guid_t *ddsi2guid, nn_wctime_t timestamp)
 | 
			
		||||
static void make_participants_dependent_on_ddsi2 (struct q_globals *gv, const ddsi_guid_t *ddsi2guid, nn_wctime_t timestamp)
 | 
			
		||||
{
 | 
			
		||||
  struct ephash_enum_proxy_participant it;
 | 
			
		||||
  struct proxy_participant *pp, *d2pp;
 | 
			
		||||
| 
						 | 
				
			
			@ -514,17 +514,16 @@ static int handle_SPDP_alive (const struct receiver_state *rst, seqno_t seq, nn_
 | 
			
		|||
    NN_DISC_BUILTIN_ENDPOINT_SUBSCRIPTION_ANNOUNCER |
 | 
			
		||||
    NN_DISC_BUILTIN_ENDPOINT_PUBLICATION_ANNOUNCER;
 | 
			
		||||
  struct addrset *as_meta, *as_default;
 | 
			
		||||
  struct proxy_participant *proxypp;
 | 
			
		||||
  unsigned builtin_endpoint_set;
 | 
			
		||||
  unsigned prismtech_builtin_endpoint_set;
 | 
			
		||||
  nn_guid_t privileged_pp_guid;
 | 
			
		||||
  ddsi_guid_t privileged_pp_guid;
 | 
			
		||||
  dds_duration_t lease_duration;
 | 
			
		||||
  unsigned custom_flags = 0;
 | 
			
		||||
 | 
			
		||||
  if (!(datap->present & PP_PARTICIPANT_GUID) || !(datap->present & PP_BUILTIN_ENDPOINT_SET))
 | 
			
		||||
  {
 | 
			
		||||
    GVWARNING ("data (SPDP, vendor %u.%u): no/invalid payload\n", rst->vendor.id[0], rst->vendor.id[1]);
 | 
			
		||||
    return 1;
 | 
			
		||||
    return 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /* At some point the RTI implementation didn't mention
 | 
			
		||||
| 
						 | 
				
			
			@ -563,49 +562,56 @@ static int handle_SPDP_alive (const struct receiver_state *rst, seqno_t seq, nn_
 | 
			
		|||
        prismtech_builtin_endpoint_set |= NN_DISC_BUILTIN_ENDPOINT_CM_PUBLISHER_WRITER | NN_DISC_BUILTIN_ENDPOINT_CM_SUBSCRIBER_WRITER;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /* Local SPDP packets may be looped back, and that may include ones
 | 
			
		||||
     currently being deleted.  The first thing that happens when
 | 
			
		||||
     deleting a participant is removing it from the hash table, and
 | 
			
		||||
     consequently the looped back packet may appear to be from an
 | 
			
		||||
     unknown participant.  So we handle that, too. */
 | 
			
		||||
 | 
			
		||||
  if (is_deleted_participant_guid (gv->deleted_participants, &datap->participant_guid, DPG_REMOTE))
 | 
			
		||||
  /* Do we know this GUID already? */
 | 
			
		||||
  {
 | 
			
		||||
    RSTTRACE ("SPDP ST0 "PGUIDFMT" (recently deleted)", PGUID (datap->participant_guid));
 | 
			
		||||
    return 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  {
 | 
			
		||||
    int islocal = 0;
 | 
			
		||||
    if (ephash_lookup_participant_guid (gv->guid_hash, &datap->participant_guid))
 | 
			
		||||
      islocal = 1;
 | 
			
		||||
    if (islocal)
 | 
			
		||||
    struct entity_common *existing_entity;
 | 
			
		||||
    if ((existing_entity = ephash_lookup_guid_untyped (gv->guid_hash, &datap->participant_guid)) == NULL)
 | 
			
		||||
    {
 | 
			
		||||
      RSTTRACE ("SPDP ST0 "PGUIDFMT" (local %d)", PGUID (datap->participant_guid), islocal);
 | 
			
		||||
      /* Local SPDP packets may be looped back, and that can include ones
 | 
			
		||||
         for participants currently being deleted.  The first thing that
 | 
			
		||||
         happens when deleting a participant is removing it from the hash
 | 
			
		||||
         table, and consequently the looped back packet may appear to be
 | 
			
		||||
         from an unknown participant.  So we handle that. */
 | 
			
		||||
      if (is_deleted_participant_guid (gv->deleted_participants, &datap->participant_guid, DPG_REMOTE))
 | 
			
		||||
      {
 | 
			
		||||
        RSTTRACE ("SPDP ST0 "PGUIDFMT" (recently deleted)", PGUID (datap->participant_guid));
 | 
			
		||||
        return 0;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    else if (existing_entity->kind == EK_PARTICIPANT)
 | 
			
		||||
    {
 | 
			
		||||
      RSTTRACE ("SPDP ST0 "PGUIDFMT" (local)", PGUID (datap->participant_guid));
 | 
			
		||||
      return 0;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if ((proxypp = ephash_lookup_proxy_participant_guid (gv->guid_hash, &datap->participant_guid)) != NULL)
 | 
			
		||||
  {
 | 
			
		||||
    /* SPDP processing is so different from normal processing that we
 | 
			
		||||
       are even skipping the automatic lease renewal.  Therefore do it
 | 
			
		||||
       regardless of
 | 
			
		||||
       gv.config.arrival_of_data_asserts_pp_and_ep_liveliness. */
 | 
			
		||||
    RSTTRACE ("SPDP ST0 "PGUIDFMT" (known)", PGUID (datap->participant_guid));
 | 
			
		||||
    lease_renew (ddsrt_atomic_ldvoidp (&proxypp->lease), now_et ());
 | 
			
		||||
    ddsrt_mutex_lock (&proxypp->e.lock);
 | 
			
		||||
    if (proxypp->implicitly_created || seq > proxypp->seq)
 | 
			
		||||
    else if (existing_entity->kind == EK_PROXY_PARTICIPANT)
 | 
			
		||||
    {
 | 
			
		||||
      if (proxypp->implicitly_created)
 | 
			
		||||
        GVLOGDISC (" (NEW was-implicitly-created)");
 | 
			
		||||
      else
 | 
			
		||||
        GVLOGDISC (" (update)");
 | 
			
		||||
      proxypp->implicitly_created = 0;
 | 
			
		||||
      update_proxy_participant_plist_locked (proxypp, seq, datap, UPD_PROXYPP_SPDP, timestamp);
 | 
			
		||||
      struct proxy_participant *proxypp = (struct proxy_participant *) existing_entity;
 | 
			
		||||
      int interesting = 0;
 | 
			
		||||
      RSTTRACE ("SPDP ST0 "PGUIDFMT" (known)", PGUID (datap->participant_guid));
 | 
			
		||||
      /* SPDP processing is so different from normal processing that we are
 | 
			
		||||
         even skipping the automatic lease renewal.  Therefore do it regardless
 | 
			
		||||
         of gv.config.arrival_of_data_asserts_pp_and_ep_liveliness. */
 | 
			
		||||
      lease_renew (ddsrt_atomic_ldvoidp (&proxypp->lease), now_et ());
 | 
			
		||||
      ddsrt_mutex_lock (&proxypp->e.lock);
 | 
			
		||||
      if (proxypp->implicitly_created || seq > proxypp->seq)
 | 
			
		||||
      {
 | 
			
		||||
        interesting = 1;
 | 
			
		||||
        if (!(gv->logconfig.c.mask & DDS_LC_TRACE))
 | 
			
		||||
          GVLOGDISC ("SPDP ST0 "PGUIDFMT, PGUID (datap->participant_guid));
 | 
			
		||||
        GVLOGDISC (proxypp->implicitly_created ? " (NEW was-implicitly-created)" : " (update)");
 | 
			
		||||
        proxypp->implicitly_created = 0;
 | 
			
		||||
        update_proxy_participant_plist_locked (proxypp, seq, datap, UPD_PROXYPP_SPDP, timestamp);
 | 
			
		||||
      }
 | 
			
		||||
      ddsrt_mutex_unlock (&proxypp->e.lock);
 | 
			
		||||
      return interesting;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
      /* mismatch on entity kind: that should never have gotten past the
 | 
			
		||||
         input validation */
 | 
			
		||||
      GVWARNING ("data (SPDP, vendor %u.%u): "PGUIDFMT" kind mismatch\n", rst->vendor.id[0], rst->vendor.id[1], PGUID (datap->participant_guid));
 | 
			
		||||
      return 0;
 | 
			
		||||
    }
 | 
			
		||||
    ddsrt_mutex_unlock (&proxypp->e.lock);
 | 
			
		||||
    return 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  GVLOGDISC ("SPDP ST0 "PGUIDFMT" bes %x ptbes %x NEW", PGUID (datap->participant_guid), builtin_endpoint_set, prismtech_builtin_endpoint_set);
 | 
			
		||||
| 
						 | 
				
			
			@ -646,7 +652,7 @@ static int handle_SPDP_alive (const struct receiver_state *rst, seqno_t seq, nn_
 | 
			
		|||
  privileged_pp_guid.prefix = rst->src_guid_prefix;
 | 
			
		||||
  privileged_pp_guid.entityid.u = NN_ENTITYID_PARTICIPANT;
 | 
			
		||||
  if ((builtin_endpoint_set & bes_sedp_announcer_mask) != bes_sedp_announcer_mask &&
 | 
			
		||||
      memcmp (&privileged_pp_guid, &datap->participant_guid, sizeof (nn_guid_t)) != 0)
 | 
			
		||||
      memcmp (&privileged_pp_guid, &datap->participant_guid, sizeof (ddsi_guid_t)) != 0)
 | 
			
		||||
  {
 | 
			
		||||
    GVLOGDISC (" (depends on "PGUIDFMT")", PGUID (privileged_pp_guid));
 | 
			
		||||
    /* never expire lease for this proxy: it won't actually expire
 | 
			
		||||
| 
						 | 
				
			
			@ -791,10 +797,9 @@ static void handle_SPDP (const struct receiver_state *rst, seqno_t seq, nn_wctim
 | 
			
		|||
{
 | 
			
		||||
  struct q_globals * const gv = rst->gv;
 | 
			
		||||
  const struct CDRHeader *data = vdata; /* built-ins not deserialized (yet) */
 | 
			
		||||
  RSTTRACE("SPDP ST%x", statusinfo);
 | 
			
		||||
  if (data == NULL)
 | 
			
		||||
  {
 | 
			
		||||
    RSTTRACE(" no payload?\n");
 | 
			
		||||
    RSTTRACE ("SPDP ST%x no payload?\n", statusinfo);
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
| 
						 | 
				
			
			@ -881,7 +886,7 @@ static void add_locator_to_ps (const nn_locator_t *loc, void *varg)
 | 
			
		|||
 | 
			
		||||
static int sedp_write_endpoint
 | 
			
		||||
(
 | 
			
		||||
   struct writer *wr, int alive, const nn_guid_t *epguid,
 | 
			
		||||
   struct writer *wr, int alive, const ddsi_guid_t *epguid,
 | 
			
		||||
   const struct entity_common *common, const struct endpoint_common *epcommon,
 | 
			
		||||
   const dds_qos_t *xqos, struct addrset *as)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -1040,9 +1045,9 @@ static const char *durability_to_string (dds_durability_kind_t k)
 | 
			
		|||
  return "undefined-durability";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct proxy_participant *implicitly_create_proxypp (struct q_globals *gv, const nn_guid_t *ppguid, nn_plist_t *datap /* note: potentially modifies datap */, const nn_guid_prefix_t *src_guid_prefix, nn_vendorid_t vendorid, nn_wctime_t timestamp, seqno_t seq)
 | 
			
		||||
static struct proxy_participant *implicitly_create_proxypp (struct q_globals *gv, const ddsi_guid_t *ppguid, nn_plist_t *datap /* note: potentially modifies datap */, const ddsi_guid_prefix_t *src_guid_prefix, nn_vendorid_t vendorid, nn_wctime_t timestamp, seqno_t seq)
 | 
			
		||||
{
 | 
			
		||||
  nn_guid_t privguid;
 | 
			
		||||
  ddsi_guid_t privguid;
 | 
			
		||||
  nn_plist_t pp_plist;
 | 
			
		||||
 | 
			
		||||
  if (memcmp (&ppguid->prefix, src_guid_prefix, sizeof (ppguid->prefix)) == 0)
 | 
			
		||||
| 
						 | 
				
			
			@ -1120,14 +1125,14 @@ static struct proxy_participant *implicitly_create_proxypp (struct q_globals *gv
 | 
			
		|||
  return ephash_lookup_proxy_participant_guid (gv->guid_hash, ppguid);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_SEDP_alive (const struct receiver_state *rst, seqno_t seq, nn_plist_t *datap /* note: potentially modifies datap */, const nn_guid_prefix_t *src_guid_prefix, nn_vendorid_t vendorid, nn_wctime_t timestamp)
 | 
			
		||||
static void handle_SEDP_alive (const struct receiver_state *rst, seqno_t seq, nn_plist_t *datap /* note: potentially modifies datap */, const ddsi_guid_prefix_t *src_guid_prefix, nn_vendorid_t vendorid, nn_wctime_t timestamp)
 | 
			
		||||
{
 | 
			
		||||
#define E(msg, lbl) do { GVLOGDISC (msg); goto lbl; } while (0)
 | 
			
		||||
  struct q_globals * const gv = rst->gv;
 | 
			
		||||
  struct proxy_participant *pp;
 | 
			
		||||
  struct proxy_writer * pwr = NULL;
 | 
			
		||||
  struct proxy_reader * prd = NULL;
 | 
			
		||||
  nn_guid_t ppguid;
 | 
			
		||||
  ddsi_guid_t ppguid;
 | 
			
		||||
  dds_qos_t *xqos;
 | 
			
		||||
  int reliable;
 | 
			
		||||
  struct addrset *as;
 | 
			
		||||
| 
						 | 
				
			
			@ -1466,7 +1471,7 @@ int sedp_write_cm_participant (struct participant *pp, int alive)
 | 
			
		|||
  return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_SEDP_CM (const struct receiver_state *rst, nn_entityid_t wr_entity_id, nn_wctime_t timestamp, uint32_t statusinfo, const void *vdata, uint32_t len)
 | 
			
		||||
static void handle_SEDP_CM (const struct receiver_state *rst, ddsi_entityid_t wr_entity_id, nn_wctime_t timestamp, uint32_t statusinfo, const void *vdata, uint32_t len)
 | 
			
		||||
{
 | 
			
		||||
  struct q_globals * const gv = rst->gv;
 | 
			
		||||
  const struct CDRHeader *data = vdata; /* built-ins not deserialized (yet) */
 | 
			
		||||
| 
						 | 
				
			
			@ -1552,7 +1557,7 @@ static int defragment (unsigned char **datap, const struct nn_rdata *fragchain,
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int builtins_dqueue_handler (const struct nn_rsample_info *sampleinfo, const struct nn_rdata *fragchain, UNUSED_ARG (const nn_guid_t *rdguid), UNUSED_ARG (void *qarg))
 | 
			
		||||
int builtins_dqueue_handler (const struct nn_rsample_info *sampleinfo, const struct nn_rdata *fragchain, UNUSED_ARG (const ddsi_guid_t *rdguid), UNUSED_ARG (void *qarg))
 | 
			
		||||
{
 | 
			
		||||
  struct q_globals * const gv = sampleinfo->rst->gv;
 | 
			
		||||
  struct proxy_writer *pwr;
 | 
			
		||||
| 
						 | 
				
			
			@ -1564,7 +1569,7 @@ int builtins_dqueue_handler (const struct nn_rsample_info *sampleinfo, const str
 | 
			
		|||
  } keyhash_payload;
 | 
			
		||||
  unsigned statusinfo;
 | 
			
		||||
  int need_keyhash;
 | 
			
		||||
  nn_guid_t srcguid;
 | 
			
		||||
  ddsi_guid_t srcguid;
 | 
			
		||||
  Data_DataFrag_common_t *msg;
 | 
			
		||||
  unsigned char data_smhdr_flags;
 | 
			
		||||
  nn_plist_t qos;
 | 
			
		||||
| 
						 | 
				
			
			@ -1643,7 +1648,6 @@ int builtins_dqueue_handler (const struct nn_rsample_info *sampleinfo, const str
 | 
			
		|||
 | 
			
		||||
  /* Built-ins still do their own deserialization (SPDP <=> pwr ==
 | 
			
		||||
     NULL)). */
 | 
			
		||||
  assert (pwr == NULL || pwr->c.topic == NULL);
 | 
			
		||||
  if (statusinfo == 0)
 | 
			
		||||
  {
 | 
			
		||||
    if (datasz == 0 || !(data_smhdr_flags & DATA_FLAG_DATAFLAG))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -57,6 +57,8 @@ struct debug_monitor {
 | 
			
		|||
  int stop;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int cpf (ddsi_tran_conn_t conn, const char *fmt, ...) ddsrt_attribute_format ((printf, 2, 3));
 | 
			
		||||
 | 
			
		||||
static int cpf (ddsi_tran_conn_t conn, const char *fmt, ...)
 | 
			
		||||
{
 | 
			
		||||
  nn_locator_t loc;
 | 
			
		||||
| 
						 | 
				
			
			@ -107,35 +109,34 @@ static int print_addrset_if_notempty (ddsi_tran_conn_t conn, const char *prefix,
 | 
			
		|||
    return print_addrset (conn, prefix, as, suffix);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int print_any_endpoint_common (ddsi_tran_conn_t conn, const char *label, const struct entity_common *e,
 | 
			
		||||
                                      const struct dds_qos *xqos, const struct ddsi_sertopic *topic)
 | 
			
		||||
static int print_any_endpoint_common (ddsi_tran_conn_t conn, const char *label, const struct entity_common *e, const struct dds_qos *xqos)
 | 
			
		||||
{
 | 
			
		||||
  int x = 0;
 | 
			
		||||
  x += cpf (conn, "  %s %x:%x:%x:%x ", label, PGUID (e->guid));
 | 
			
		||||
  x += cpf (conn, "  %s "PGUIDFMT" ", label, PGUID (e->guid));
 | 
			
		||||
  if (xqos->present & QP_PARTITION)
 | 
			
		||||
  {
 | 
			
		||||
    if (xqos->partition.n > 1) cpf (conn, "{");
 | 
			
		||||
    for (uint32_t i = 0; i < xqos->partition.n; i++)
 | 
			
		||||
      x += cpf (conn, "%s%s", i == 0 ? "" : ",", xqos->partition.strs[i]);
 | 
			
		||||
    if (xqos->partition.n > 1) cpf (conn, "}");
 | 
			
		||||
    x += cpf (conn, ".%s/%s",
 | 
			
		||||
              topic && topic->name ? topic->name : (xqos->present & QP_TOPIC_NAME) ? xqos->topic_name : "(null)",
 | 
			
		||||
              topic && topic->type_name ? topic->type_name : (xqos->present & QP_TYPE_NAME) ? xqos->type_name : "(null)");
 | 
			
		||||
    const char *topic_name = (xqos->present & QP_TOPIC_NAME) ? xqos->topic_name : "null";
 | 
			
		||||
    const char *topic_typename = (xqos->present & QP_TYPE_NAME) ? xqos->type_name : "null";
 | 
			
		||||
    x += cpf (conn, ".%s/%s", topic_name, topic_typename);
 | 
			
		||||
  }
 | 
			
		||||
  cpf (conn, "\n");
 | 
			
		||||
  return x;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int print_endpoint_common (ddsi_tran_conn_t conn, const char *label, const struct entity_common *e, const struct endpoint_common *c, const struct dds_qos *xqos, const struct ddsi_sertopic *topic)
 | 
			
		||||
static int print_endpoint_common (ddsi_tran_conn_t conn, const char *label, const struct entity_common *e, const struct endpoint_common *c, const struct dds_qos *xqos)
 | 
			
		||||
{
 | 
			
		||||
  DDSRT_UNUSED_ARG (c);
 | 
			
		||||
  return print_any_endpoint_common (conn, label, e, xqos, topic);
 | 
			
		||||
  return print_any_endpoint_common (conn, label, e, xqos);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int print_proxy_endpoint_common (ddsi_tran_conn_t conn, const char *label, const struct entity_common *e, const struct proxy_endpoint_common *c)
 | 
			
		||||
{
 | 
			
		||||
  int x = 0;
 | 
			
		||||
  x += print_any_endpoint_common (conn, label, e, c->xqos, c->topic);
 | 
			
		||||
  x += print_any_endpoint_common (conn, label, e, c->xqos);
 | 
			
		||||
  x += print_addrset_if_notempty (conn, "    as", c->as, "\n");
 | 
			
		||||
  return x;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -151,7 +152,7 @@ static int print_participants (struct thread_state1 * const ts1, struct q_global
 | 
			
		|||
  while ((p = ephash_enum_participant_next (&e)) != NULL)
 | 
			
		||||
  {
 | 
			
		||||
    ddsrt_mutex_lock (&p->e.lock);
 | 
			
		||||
    x += cpf (conn, "pp %x:%x:%x:%x %s%s\n", PGUID (p->e.guid), p->e.name, p->is_ddsi2_pp ? " [ddsi2]" : "");
 | 
			
		||||
    x += cpf (conn, "pp "PGUIDFMT" %s%s\n", PGUID (p->e.guid), p->e.name, p->is_ddsi2_pp ? " [ddsi2]" : "");
 | 
			
		||||
    ddsrt_mutex_unlock (&p->e.lock);
 | 
			
		||||
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -165,12 +166,12 @@ static int print_participants (struct thread_state1 * const ts1, struct q_global
 | 
			
		|||
        if (r->c.pp != p)
 | 
			
		||||
          continue;
 | 
			
		||||
        ddsrt_mutex_lock (&r->e.lock);
 | 
			
		||||
        print_endpoint_common (conn, "rd", &r->e, &r->c, r->xqos, r->topic);
 | 
			
		||||
        print_endpoint_common (conn, "rd", &r->e, &r->c, r->xqos);
 | 
			
		||||
#ifdef DDSI_INCLUDE_NETWORK_PARTITIONS
 | 
			
		||||
        x += print_addrset_if_notempty (conn, "    as", r->as, "\n");
 | 
			
		||||
#endif
 | 
			
		||||
        for (m = ddsrt_avl_iter_first (&rd_writers_treedef, &r->writers, &writ); m; m = ddsrt_avl_iter_next (&writ))
 | 
			
		||||
          x += cpf (conn, "    pwr %x:%x:%x:%x\n", PGUID (m->pwr_guid));
 | 
			
		||||
          x += cpf (conn, "    pwr "PGUIDFMT"\n", PGUID (m->pwr_guid));
 | 
			
		||||
        ddsrt_mutex_unlock (&r->e.lock);
 | 
			
		||||
      }
 | 
			
		||||
      ephash_enum_reader_fini (&er);
 | 
			
		||||
| 
						 | 
				
			
			@ -188,22 +189,22 @@ static int print_participants (struct thread_state1 * const ts1, struct q_global
 | 
			
		|||
        if (w->c.pp != p)
 | 
			
		||||
          continue;
 | 
			
		||||
        ddsrt_mutex_lock (&w->e.lock);
 | 
			
		||||
        print_endpoint_common (conn, "wr", &w->e, &w->c, w->xqos, w->topic);
 | 
			
		||||
        print_endpoint_common (conn, "wr", &w->e, &w->c, w->xqos);
 | 
			
		||||
        whc_get_state(w->whc, &whcst);
 | 
			
		||||
        x += cpf (conn, "    whc [%lld,%lld] unacked %"PRIuSIZE"%s [%u,%u] seq %lld seq_xmit %lld cs_seq %lld\n",
 | 
			
		||||
        x += cpf (conn, "    whc [%"PRId64",%"PRId64"] unacked %"PRIuSIZE"%s [%"PRIu32",%"PRIu32"] seq %"PRId64" seq_xmit %"PRId64" cs_seq %"PRId64"\n",
 | 
			
		||||
                  whcst.min_seq, whcst.max_seq, whcst.unacked_bytes,
 | 
			
		||||
                  w->throttling ? " THROTTLING" : "",
 | 
			
		||||
                  w->whc_low, w->whc_high,
 | 
			
		||||
                  w->seq, READ_SEQ_XMIT(w), w->cs_seq);
 | 
			
		||||
        if (w->reliable)
 | 
			
		||||
        {
 | 
			
		||||
          x += cpf (conn, "    hb %u ackhb %lld hb %lld wr %lld sched %lld #rel %d\n",
 | 
			
		||||
                    w->hbcontrol.hbs_since_last_write, w->hbcontrol.t_of_last_ackhb,
 | 
			
		||||
                    w->hbcontrol.t_of_last_hb, w->hbcontrol.t_of_last_write,
 | 
			
		||||
                    w->hbcontrol.tsched, w->num_reliable_readers);
 | 
			
		||||
          x += cpf (conn, "    #acks %u #nacks %u #rexmit %u #lost %u #throttle %u\n",
 | 
			
		||||
          x += cpf (conn, "    hb %"PRIu32" ackhb %"PRId64" hb %"PRId64" wr %"PRId64" sched %"PRId64" #rel %"PRId32"\n",
 | 
			
		||||
                    w->hbcontrol.hbs_since_last_write, w->hbcontrol.t_of_last_ackhb.v,
 | 
			
		||||
                    w->hbcontrol.t_of_last_hb.v, w->hbcontrol.t_of_last_write.v,
 | 
			
		||||
                    w->hbcontrol.tsched.v, w->num_reliable_readers);
 | 
			
		||||
          x += cpf (conn, "    #acks %"PRIu32" #nacks %"PRIu32" #rexmit %"PRIu32" #lost %"PRIu32" #throttle %"PRIu32"\n",
 | 
			
		||||
                    w->num_acks_received, w->num_nacks_received, w->rexmit_count, w->rexmit_lost_count, w->throttle_count);
 | 
			
		||||
          x += cpf (conn, "    max-drop-seq %lld\n", writer_max_drop_seq (w));
 | 
			
		||||
          x += cpf (conn, "    max-drop-seq %"PRId64"\n", writer_max_drop_seq (w));
 | 
			
		||||
        }
 | 
			
		||||
        x += print_addrset_if_notempty (conn, "    as", w->as, "\n");
 | 
			
		||||
        for (m = ddsrt_avl_iter_first (&wr_readers_treedef, &w->readers, &rdit); m; m = ddsrt_avl_iter_next (&rdit))
 | 
			
		||||
| 
						 | 
				
			
			@ -213,7 +214,7 @@ static int print_participants (struct thread_state1 * const ts1, struct q_global
 | 
			
		|||
          wr_prd_flags[1] = m->assumed_in_sync ? 's' : '.';
 | 
			
		||||
          wr_prd_flags[2] = m->has_replied_to_hb ? 'a' : '.'; /* a = ack seen */
 | 
			
		||||
          wr_prd_flags[3] = 0;
 | 
			
		||||
          x += cpf (conn, "    prd %x:%x:%x:%x %s @ %lld [%lld,%lld] #nacks %u\n",
 | 
			
		||||
          x += cpf (conn, "    prd "PGUIDFMT" %s @ %"PRId64" [%"PRId64",%"PRId64"] #nacks %"PRIu32"\n",
 | 
			
		||||
                    PGUID (m->prd_guid), wr_prd_flags, m->seq, m->min_seq, m->max_seq, m->rexmit_requests);
 | 
			
		||||
        }
 | 
			
		||||
        ddsrt_mutex_unlock (&w->e.lock);
 | 
			
		||||
| 
						 | 
				
			
			@ -236,7 +237,7 @@ static int print_proxy_participants (struct thread_state1 * const ts1, struct q_
 | 
			
		|||
  while ((p = ephash_enum_proxy_participant_next (&e)) != NULL)
 | 
			
		||||
  {
 | 
			
		||||
    ddsrt_mutex_lock (&p->e.lock);
 | 
			
		||||
    x += cpf (conn, "proxypp %x:%x:%x:%x%s\n", PGUID (p->e.guid), p->is_ddsi2_pp ? " [ddsi2]" : "");
 | 
			
		||||
    x += cpf (conn, "proxypp "PGUIDFMT"%s\n", PGUID (p->e.guid), p->is_ddsi2_pp ? " [ddsi2]" : "");
 | 
			
		||||
    ddsrt_mutex_unlock (&p->e.lock);
 | 
			
		||||
    x += print_addrset (conn, "  as data", p->as_default, "");
 | 
			
		||||
    x += print_addrset (conn, " meta", p->as_default, "\n");
 | 
			
		||||
| 
						 | 
				
			
			@ -254,7 +255,7 @@ static int print_proxy_participants (struct thread_state1 * const ts1, struct q_
 | 
			
		|||
        ddsrt_mutex_lock (&r->e.lock);
 | 
			
		||||
        print_proxy_endpoint_common (conn, "prd", &r->e, &r->c);
 | 
			
		||||
        for (m = ddsrt_avl_iter_first (&rd_writers_treedef, &r->writers, &writ); m; m = ddsrt_avl_iter_next (&writ))
 | 
			
		||||
          x += cpf (conn, "    wr %x:%x:%x:%x\n", PGUID (m->wr_guid));
 | 
			
		||||
          x += cpf (conn, "    wr "PGUIDFMT"\n", PGUID (m->wr_guid));
 | 
			
		||||
        ddsrt_mutex_unlock (&r->e.lock);
 | 
			
		||||
      }
 | 
			
		||||
      ephash_enum_proxy_reader_fini (&er);
 | 
			
		||||
| 
						 | 
				
			
			@ -272,20 +273,20 @@ static int print_proxy_participants (struct thread_state1 * const ts1, struct q_
 | 
			
		|||
          continue;
 | 
			
		||||
        ddsrt_mutex_lock (&w->e.lock);
 | 
			
		||||
        print_proxy_endpoint_common (conn, "pwr", &w->e, &w->c);
 | 
			
		||||
        x += cpf (conn, "    last_seq %lld last_fragnum %u\n", w->last_seq, w->last_fragnum);
 | 
			
		||||
        x += cpf (conn, "    last_seq %"PRId64" last_fragnum %"PRIu32"\n", w->last_seq, w->last_fragnum);
 | 
			
		||||
        for (m = ddsrt_avl_iter_first (&wr_readers_treedef, &w->readers, &rdit); m; m = ddsrt_avl_iter_next (&rdit))
 | 
			
		||||
        {
 | 
			
		||||
          x += cpf (conn, "    rd %x:%x:%x:%x (nack %lld %lld)\n",
 | 
			
		||||
                    PGUID (m->rd_guid), m->seq_last_nack, m->t_last_nack);
 | 
			
		||||
          x += cpf (conn, "    rd "PGUIDFMT" (nack %"PRId64" %"PRId64")\n",
 | 
			
		||||
                    PGUID (m->rd_guid), m->seq_last_nack, m->t_last_nack.v);
 | 
			
		||||
          switch (m->in_sync)
 | 
			
		||||
          {
 | 
			
		||||
            case PRMSS_SYNC:
 | 
			
		||||
              break;
 | 
			
		||||
            case PRMSS_TLCATCHUP:
 | 
			
		||||
              x += cpf (conn, "      tl-catchup end_of_tl_seq %lld\n", m->u.not_in_sync.end_of_tl_seq);
 | 
			
		||||
              x += cpf (conn, "      tl-catchup end_of_tl_seq %"PRId64"\n", m->u.not_in_sync.end_of_tl_seq);
 | 
			
		||||
              break;
 | 
			
		||||
            case PRMSS_OUT_OF_SYNC:
 | 
			
		||||
              x += cpf (conn, "      out-of-sync end_of_tl_seq %lld\n", m->u.not_in_sync.end_of_tl_seq);
 | 
			
		||||
              x += cpf (conn, "      out-of-sync end_of_tl_seq %"PRId64"\n", m->u.not_in_sync.end_of_tl_seq);
 | 
			
		||||
              break;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -42,7 +42,7 @@
 | 
			
		|||
#include "dds/ddsi/ddsi_mcgroup.h"
 | 
			
		||||
#include "dds/ddsi/q_receive.h"
 | 
			
		||||
#include "dds/ddsi/ddsi_udp.h" /* nn_mc4gen_address_t */
 | 
			
		||||
#include "dds/ddsi/q_rhc.h"
 | 
			
		||||
#include "dds/ddsi/ddsi_rhc.h"
 | 
			
		||||
 | 
			
		||||
#include "dds/ddsi/sysdeps.h"
 | 
			
		||||
#include "dds__whc.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -51,7 +51,7 @@
 | 
			
		|||
 | 
			
		||||
struct deleted_participant {
 | 
			
		||||
  ddsrt_avl_node_t avlnode;
 | 
			
		||||
  nn_guid_t guid;
 | 
			
		||||
  ddsi_guid_t guid;
 | 
			
		||||
  unsigned for_what;
 | 
			
		||||
  nn_mtime_t t_prune;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -59,6 +59,7 @@ struct deleted_participant {
 | 
			
		|||
struct deleted_participants_admin {
 | 
			
		||||
  ddsrt_mutex_t deleted_participants_lock;
 | 
			
		||||
  ddsrt_avl_tree_t deleted_participants;
 | 
			
		||||
  const ddsrt_log_cfg_t *logcfg;
 | 
			
		||||
  int64_t delay;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -92,10 +93,10 @@ static const unsigned prismtech_builtin_writers_besmask =
 | 
			
		|||
  NN_DISC_BUILTIN_ENDPOINT_CM_PUBLISHER_WRITER |
 | 
			
		||||
  NN_DISC_BUILTIN_ENDPOINT_CM_SUBSCRIBER_WRITER;
 | 
			
		||||
 | 
			
		||||
static dds_return_t new_writer_guid (struct writer **wr_out, const struct nn_guid *guid, const struct nn_guid *group_guid, struct participant *pp, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct whc *whc, status_cb_t status_cb, void *status_cbarg);
 | 
			
		||||
static dds_return_t new_reader_guid (struct reader **rd_out, const struct nn_guid *guid, const struct nn_guid *group_guid, struct participant *pp, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct rhc *rhc, status_cb_t status_cb, void *status_cbarg);
 | 
			
		||||
static struct participant *ref_participant (struct participant *pp, const struct nn_guid *guid_of_refing_entity);
 | 
			
		||||
static void unref_participant (struct participant *pp, const struct nn_guid *guid_of_refing_entity);
 | 
			
		||||
static dds_return_t new_writer_guid (struct writer **wr_out, const struct ddsi_guid *guid, const struct ddsi_guid *group_guid, struct participant *pp, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct whc *whc, status_cb_t status_cb, void *status_cbarg);
 | 
			
		||||
static dds_return_t new_reader_guid (struct reader **rd_out, const struct ddsi_guid *guid, const struct ddsi_guid *group_guid, struct participant *pp, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct ddsi_rhc *rhc, status_cb_t status_cb, void *status_cbarg);
 | 
			
		||||
static struct participant *ref_participant (struct participant *pp, const struct ddsi_guid *guid_of_refing_entity);
 | 
			
		||||
static void unref_participant (struct participant *pp, const struct ddsi_guid *guid_of_refing_entity);
 | 
			
		||||
 | 
			
		||||
static int gcreq_participant (struct participant *pp);
 | 
			
		||||
static int gcreq_writer (struct writer *wr);
 | 
			
		||||
| 
						 | 
				
			
			@ -104,24 +105,29 @@ static int gcreq_proxy_participant (struct proxy_participant *proxypp);
 | 
			
		|||
static int gcreq_proxy_writer (struct proxy_writer *pwr);
 | 
			
		||||
static int gcreq_proxy_reader (struct proxy_reader *prd);
 | 
			
		||||
 | 
			
		||||
extern inline bool builtintopic_is_visible (const struct ddsi_builtin_topic_interface *btif, const struct nn_guid *guid, nn_vendorid_t vendorid);
 | 
			
		||||
extern inline bool builtintopic_is_visible (const struct ddsi_builtin_topic_interface *btif, const struct ddsi_guid *guid, nn_vendorid_t vendorid);
 | 
			
		||||
extern inline bool builtintopic_is_builtintopic (const struct ddsi_builtin_topic_interface *btif, const struct ddsi_sertopic *topic);
 | 
			
		||||
extern inline struct ddsi_tkmap_instance *builtintopic_get_tkmap_entry (const struct ddsi_builtin_topic_interface *btif, const struct nn_guid *guid);
 | 
			
		||||
extern inline struct ddsi_tkmap_instance *builtintopic_get_tkmap_entry (const struct ddsi_builtin_topic_interface *btif, const struct ddsi_guid *guid);
 | 
			
		||||
extern inline void builtintopic_write (const struct ddsi_builtin_topic_interface *btif, const struct entity_common *e, nn_wctime_t timestamp, bool alive);
 | 
			
		||||
 | 
			
		||||
static int compare_guid (const void *va, const void *vb)
 | 
			
		||||
{
 | 
			
		||||
  return memcmp (va, vb, sizeof (nn_guid_t));
 | 
			
		||||
  return memcmp (va, vb, sizeof (ddsi_guid_t));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
nn_entityid_t to_entityid (unsigned u)
 | 
			
		||||
bool is_null_guid (const ddsi_guid_t *guid)
 | 
			
		||||
{
 | 
			
		||||
  nn_entityid_t e;
 | 
			
		||||
  return guid->prefix.u[0] == 0 && guid->prefix.u[1] == 0 && guid->prefix.u[2] == 0 && guid->entityid.u == 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ddsi_entityid_t to_entityid (unsigned u)
 | 
			
		||||
{
 | 
			
		||||
  ddsi_entityid_t e;
 | 
			
		||||
  e.u = u;
 | 
			
		||||
  return e;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int is_writer_entityid (nn_entityid_t id)
 | 
			
		||||
int is_writer_entityid (ddsi_entityid_t id)
 | 
			
		||||
{
 | 
			
		||||
  switch (id.u & NN_ENTITYID_KIND_MASK)
 | 
			
		||||
  {
 | 
			
		||||
| 
						 | 
				
			
			@ -133,7 +139,7 @@ int is_writer_entityid (nn_entityid_t id)
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int is_reader_entityid (nn_entityid_t id)
 | 
			
		||||
int is_reader_entityid (ddsi_entityid_t id)
 | 
			
		||||
{
 | 
			
		||||
  switch (id.u & NN_ENTITYID_KIND_MASK)
 | 
			
		||||
  {
 | 
			
		||||
| 
						 | 
				
			
			@ -145,7 +151,7 @@ int is_reader_entityid (nn_entityid_t id)
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int is_keyed_endpoint_entityid (nn_entityid_t id)
 | 
			
		||||
int is_keyed_endpoint_entityid (ddsi_entityid_t id)
 | 
			
		||||
{
 | 
			
		||||
  switch (id.u & NN_ENTITYID_KIND_MASK)
 | 
			
		||||
  {
 | 
			
		||||
| 
						 | 
				
			
			@ -160,7 +166,7 @@ int is_keyed_endpoint_entityid (nn_entityid_t id)
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int is_builtin_entityid (nn_entityid_t id, nn_vendorid_t vendorid)
 | 
			
		||||
int is_builtin_entityid (ddsi_entityid_t id, nn_vendorid_t vendorid)
 | 
			
		||||
{
 | 
			
		||||
  if ((id.u & NN_ENTITYID_SOURCE_MASK) == NN_ENTITYID_SOURCE_BUILTIN)
 | 
			
		||||
    return 1;
 | 
			
		||||
| 
						 | 
				
			
			@ -175,7 +181,7 @@ int is_builtin_entityid (nn_entityid_t id, nn_vendorid_t vendorid)
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int is_builtin_endpoint (nn_entityid_t id, nn_vendorid_t vendorid)
 | 
			
		||||
int is_builtin_endpoint (ddsi_entityid_t id, nn_vendorid_t vendorid)
 | 
			
		||||
{
 | 
			
		||||
  return is_builtin_entityid (id, vendorid) && id.u != NN_ENTITYID_PARTICIPANT;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -186,7 +192,7 @@ bool is_local_orphan_endpoint (const struct entity_common *e)
 | 
			
		|||
          is_builtin_endpoint (e->guid.entityid, NN_VENDORID_ECLIPSE));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void entity_common_init (struct entity_common *e, struct q_globals *gv, const struct nn_guid *guid, const char *name, enum entity_kind kind, nn_wctime_t tcreate, nn_vendorid_t vendorid, bool onlylocal)
 | 
			
		||||
static void entity_common_init (struct entity_common *e, struct q_globals *gv, const struct ddsi_guid *guid, const char *name, enum entity_kind kind, nn_wctime_t tcreate, nn_vendorid_t vendorid, bool onlylocal)
 | 
			
		||||
{
 | 
			
		||||
  e->guid = *guid;
 | 
			
		||||
  e->kind = kind;
 | 
			
		||||
| 
						 | 
				
			
			@ -296,13 +302,22 @@ nn_vendorid_t get_entity_vendorid (const struct entity_common *e)
 | 
			
		|||
  return NN_VENDORID_UNKNOWN;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ddsi_make_writer_info(struct ddsi_writer_info *wrinfo, const struct entity_common *e, const struct dds_qos *xqos)
 | 
			
		||||
{
 | 
			
		||||
  wrinfo->guid = e->guid;
 | 
			
		||||
  wrinfo->ownership_strength = xqos->ownership_strength.value;
 | 
			
		||||
  wrinfo->auto_dispose = xqos->writer_data_lifecycle.autodispose_unregistered_instances;
 | 
			
		||||
  wrinfo->iid = e->iid;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* DELETED PARTICIPANTS --------------------------------------------- */
 | 
			
		||||
 | 
			
		||||
struct deleted_participants_admin *deleted_participants_admin_new (int64_t delay)
 | 
			
		||||
struct deleted_participants_admin *deleted_participants_admin_new (const ddsrt_log_cfg_t *logcfg, int64_t delay)
 | 
			
		||||
{
 | 
			
		||||
  struct deleted_participants_admin *admin = ddsrt_malloc (sizeof (*admin));
 | 
			
		||||
  ddsrt_mutex_init (&admin->deleted_participants_lock);
 | 
			
		||||
  ddsrt_avl_init (&deleted_participants_treedef, &admin->deleted_participants);
 | 
			
		||||
  admin->logcfg = logcfg;
 | 
			
		||||
  admin->delay = delay;
 | 
			
		||||
  return admin;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -326,6 +341,7 @@ static void prune_deleted_participant_guids_unlocked (struct deleted_participant
 | 
			
		|||
    struct deleted_participant *dpp1 = ddsrt_avl_find_succ (&deleted_participants_treedef, &admin->deleted_participants, dpp);
 | 
			
		||||
    if (dpp->t_prune.v < tnow.v)
 | 
			
		||||
    {
 | 
			
		||||
      DDS_CLOG (DDS_LC_DISCOVERY, admin->logcfg, "prune_deleted_participant_guid("PGUIDFMT")\n", PGUID (dpp->guid));
 | 
			
		||||
      ddsrt_avl_delete (&deleted_participants_treedef, &admin->deleted_participants, dpp);
 | 
			
		||||
      ddsrt_free (dpp);
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -340,7 +356,7 @@ static void prune_deleted_participant_guids (struct deleted_participants_admin *
 | 
			
		|||
  ddsrt_mutex_unlock (&admin->deleted_participants_lock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void remember_deleted_participant_guid (struct deleted_participants_admin *admin, const struct nn_guid *guid)
 | 
			
		||||
static void remember_deleted_participant_guid (struct deleted_participants_admin *admin, const struct ddsi_guid *guid)
 | 
			
		||||
{
 | 
			
		||||
  struct deleted_participant *n;
 | 
			
		||||
  ddsrt_avl_ipath_t path;
 | 
			
		||||
| 
						 | 
				
			
			@ -358,7 +374,7 @@ static void remember_deleted_participant_guid (struct deleted_participants_admin
 | 
			
		|||
  ddsrt_mutex_unlock (&admin->deleted_participants_lock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int is_deleted_participant_guid (struct deleted_participants_admin *admin, const struct nn_guid *guid, unsigned for_what)
 | 
			
		||||
int is_deleted_participant_guid (struct deleted_participants_admin *admin, const struct ddsi_guid *guid, unsigned for_what)
 | 
			
		||||
{
 | 
			
		||||
  struct deleted_participant *n;
 | 
			
		||||
  int known;
 | 
			
		||||
| 
						 | 
				
			
			@ -372,17 +388,16 @@ int is_deleted_participant_guid (struct deleted_participants_admin *admin, const
 | 
			
		|||
  return known;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void remove_deleted_participant_guid (ddsrt_log_cfg_t *logcfg, struct deleted_participants_admin *admin, const struct nn_guid *guid, unsigned for_what)
 | 
			
		||||
static void remove_deleted_participant_guid (struct deleted_participants_admin *admin, const struct ddsi_guid *guid, unsigned for_what)
 | 
			
		||||
{
 | 
			
		||||
  struct deleted_participant *n;
 | 
			
		||||
  DDS_CLOG (DDS_LC_DISCOVERY, logcfg, "remove_deleted_participant_guid("PGUIDFMT" for_what=%x)\n", PGUID (*guid), for_what);
 | 
			
		||||
  DDS_CLOG (DDS_LC_DISCOVERY, admin->logcfg, "remove_deleted_participant_guid("PGUIDFMT" for_what=%x)\n", PGUID (*guid), for_what);
 | 
			
		||||
  ddsrt_mutex_lock (&admin->deleted_participants_lock);
 | 
			
		||||
  if ((n = ddsrt_avl_lookup (&deleted_participants_treedef, &admin->deleted_participants, guid)) != NULL)
 | 
			
		||||
    n->t_prune = add_duration_to_mtime (now_mt (), admin->delay);
 | 
			
		||||
  ddsrt_mutex_unlock (&admin->deleted_participants_lock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* PARTICIPANT ------------------------------------------------------ */
 | 
			
		||||
 | 
			
		||||
static bool update_qos_locked (struct entity_common *e, dds_qos_t *ent_qos, const dds_qos_t *xqos, nn_wctime_t timestamp)
 | 
			
		||||
| 
						 | 
				
			
			@ -417,7 +432,7 @@ static bool update_qos_locked (struct entity_common *e, dds_qos_t *ent_qos, cons
 | 
			
		|||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static dds_return_t pp_allocate_entityid(nn_entityid_t *id, uint32_t kind, struct participant *pp)
 | 
			
		||||
static dds_return_t pp_allocate_entityid(ddsi_entityid_t *id, uint32_t kind, struct participant *pp)
 | 
			
		||||
{
 | 
			
		||||
  uint32_t id1;
 | 
			
		||||
  int ret = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -436,17 +451,17 @@ static dds_return_t pp_allocate_entityid(nn_entityid_t *id, uint32_t kind, struc
 | 
			
		|||
  return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void pp_release_entityid(struct participant *pp, nn_entityid_t id)
 | 
			
		||||
static void pp_release_entityid(struct participant *pp, ddsi_entityid_t id)
 | 
			
		||||
{
 | 
			
		||||
  ddsrt_mutex_lock (&pp->e.lock);
 | 
			
		||||
  inverse_uint32_set_free(&pp->avail_entityids.x, id.u / NN_ENTITYID_ALLOCSTEP);
 | 
			
		||||
  ddsrt_mutex_unlock (&pp->e.lock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dds_return_t new_participant_guid (const nn_guid_t *ppguid, struct q_globals *gv, unsigned flags, const nn_plist_t *plist)
 | 
			
		||||
dds_return_t new_participant_guid (const ddsi_guid_t *ppguid, struct q_globals *gv, unsigned flags, const nn_plist_t *plist)
 | 
			
		||||
{
 | 
			
		||||
  struct participant *pp;
 | 
			
		||||
  nn_guid_t subguid, group_guid;
 | 
			
		||||
  ddsi_guid_t subguid, group_guid;
 | 
			
		||||
 | 
			
		||||
  /* no reserved bits may be set */
 | 
			
		||||
  assert ((flags & ~(RTPS_PF_NO_BUILTIN_READERS | RTPS_PF_NO_BUILTIN_WRITERS | RTPS_PF_PRIVILEGED_PP | RTPS_PF_IS_DDSI2_PP | RTPS_PF_ONLY_LOCAL)) == 0);
 | 
			
		||||
| 
						 | 
				
			
			@ -699,20 +714,16 @@ dds_return_t new_participant_guid (const nn_guid_t *ppguid, struct q_globals *gv
 | 
			
		|||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dds_return_t new_participant (nn_guid_t *p_ppguid, struct q_globals *gv, unsigned flags, const nn_plist_t *plist)
 | 
			
		||||
dds_return_t new_participant (ddsi_guid_t *p_ppguid, struct q_globals *gv, unsigned flags, const nn_plist_t *plist)
 | 
			
		||||
{
 | 
			
		||||
  nn_guid_t ppguid;
 | 
			
		||||
 | 
			
		||||
  ddsrt_mutex_lock (&gv->privileged_pp_lock);
 | 
			
		||||
  ppguid = gv->next_ppguid;
 | 
			
		||||
  if (gv->next_ppguid.prefix.u[2]++ == ~0u)
 | 
			
		||||
  {
 | 
			
		||||
    ddsrt_mutex_unlock (&gv->privileged_pp_lock);
 | 
			
		||||
    return DDS_RETCODE_OUT_OF_RESOURCES;
 | 
			
		||||
  }
 | 
			
		||||
  ddsrt_mutex_unlock (&gv->privileged_pp_lock);
 | 
			
		||||
  *p_ppguid = ppguid;
 | 
			
		||||
 | 
			
		||||
  union { uint64_t u64; uint32_t u32[2]; } u;
 | 
			
		||||
  u.u32[0] = gv->ppguid_base.prefix.u[1];
 | 
			
		||||
  u.u32[1] = gv->ppguid_base.prefix.u[2];
 | 
			
		||||
  u.u64 += ddsi_iid_gen ();
 | 
			
		||||
  p_ppguid->prefix.u[0] = gv->ppguid_base.prefix.u[0];
 | 
			
		||||
  p_ppguid->prefix.u[1] = u.u32[0];
 | 
			
		||||
  p_ppguid->prefix.u[2] = u.u32[1];
 | 
			
		||||
  p_ppguid->entityid.u = NN_ENTITYID_PARTICIPANT;
 | 
			
		||||
  return new_participant_guid (p_ppguid, gv, flags, plist);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -724,9 +735,9 @@ void update_participant_plist (struct participant *pp, const nn_plist_t *plist)
 | 
			
		|||
  ddsrt_mutex_unlock (&pp->e.lock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void delete_builtin_endpoint (struct q_globals *gv, const struct nn_guid *ppguid, unsigned entityid)
 | 
			
		||||
static void delete_builtin_endpoint (struct q_globals *gv, const struct ddsi_guid *ppguid, unsigned entityid)
 | 
			
		||||
{
 | 
			
		||||
  nn_guid_t guid;
 | 
			
		||||
  ddsi_guid_t guid;
 | 
			
		||||
  guid.prefix = ppguid->prefix;
 | 
			
		||||
  guid.entityid.u = entityid;
 | 
			
		||||
  assert (is_builtin_entityid (to_entityid (entityid), NN_VENDORID_ECLIPSE));
 | 
			
		||||
| 
						 | 
				
			
			@ -736,9 +747,9 @@ static void delete_builtin_endpoint (struct q_globals *gv, const struct nn_guid
 | 
			
		|||
    (void)delete_reader (gv, &guid);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct participant *ref_participant (struct participant *pp, const struct nn_guid *guid_of_refing_entity)
 | 
			
		||||
static struct participant *ref_participant (struct participant *pp, const struct ddsi_guid *guid_of_refing_entity)
 | 
			
		||||
{
 | 
			
		||||
  nn_guid_t stguid;
 | 
			
		||||
  ddsi_guid_t stguid;
 | 
			
		||||
  ddsrt_mutex_lock (&pp->refc_lock);
 | 
			
		||||
  if (guid_of_refing_entity && is_builtin_endpoint (guid_of_refing_entity->entityid, NN_VENDORID_ECLIPSE))
 | 
			
		||||
    pp->builtin_refc++;
 | 
			
		||||
| 
						 | 
				
			
			@ -755,7 +766,7 @@ static struct participant *ref_participant (struct participant *pp, const struct
 | 
			
		|||
  return pp;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void unref_participant (struct participant *pp, const struct nn_guid *guid_of_refing_entity)
 | 
			
		||||
static void unref_participant (struct participant *pp, const struct ddsi_guid *guid_of_refing_entity)
 | 
			
		||||
{
 | 
			
		||||
  static const unsigned builtin_endpoints_tab[] = {
 | 
			
		||||
    NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_WRITER,
 | 
			
		||||
| 
						 | 
				
			
			@ -776,7 +787,7 @@ static void unref_participant (struct participant *pp, const struct nn_guid *gui
 | 
			
		|||
    NN_ENTITYID_SEDP_BUILTIN_CM_SUBSCRIBER_WRITER,
 | 
			
		||||
    NN_ENTITYID_SEDP_BUILTIN_CM_SUBSCRIBER_READER
 | 
			
		||||
  };
 | 
			
		||||
  nn_guid_t stguid;
 | 
			
		||||
  ddsi_guid_t stguid;
 | 
			
		||||
 | 
			
		||||
  ddsrt_mutex_lock (&pp->refc_lock);
 | 
			
		||||
  if (guid_of_refing_entity && is_builtin_endpoint (guid_of_refing_entity->entityid, NN_VENDORID_ECLIPSE))
 | 
			
		||||
| 
						 | 
				
			
			@ -889,7 +900,7 @@ static void unref_participant (struct participant *pp, const struct nn_guid *gui
 | 
			
		|||
    ddsrt_free (pp->plist);
 | 
			
		||||
    ddsrt_mutex_destroy (&pp->refc_lock);
 | 
			
		||||
    entity_common_fini (&pp->e);
 | 
			
		||||
    remove_deleted_participant_guid (&pp->e.gv->logconfig, pp->e.gv->deleted_participants, &pp->e.guid, DPG_LOCAL);
 | 
			
		||||
    remove_deleted_participant_guid (pp->e.gv->deleted_participants, &pp->e.guid, DPG_LOCAL);
 | 
			
		||||
    inverse_uint32_set_fini(&pp->avail_entityids.x);
 | 
			
		||||
    ddsrt_free (pp);
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -907,9 +918,10 @@ static void gc_delete_participant (struct gcreq *gcreq)
 | 
			
		|||
  unref_participant (pp, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dds_return_t delete_participant (struct q_globals *gv, const struct nn_guid *ppguid)
 | 
			
		||||
dds_return_t delete_participant (struct q_globals *gv, const struct ddsi_guid *ppguid)
 | 
			
		||||
{
 | 
			
		||||
  struct participant *pp;
 | 
			
		||||
  GVLOGDISC ("delete_participant("PGUIDFMT")\n", PGUID (*ppguid));
 | 
			
		||||
  if ((pp = ephash_lookup_participant_guid (gv->guid_hash, ppguid)) == NULL)
 | 
			
		||||
    return DDS_RETCODE_BAD_PARAMETER;
 | 
			
		||||
  builtintopic_write (gv->builtin_topic_interface, &pp->e, now(), false);
 | 
			
		||||
| 
						 | 
				
			
			@ -921,7 +933,7 @@ dds_return_t delete_participant (struct q_globals *gv, const struct nn_guid *ppg
 | 
			
		|||
 | 
			
		||||
struct writer *get_builtin_writer (const struct participant *pp, unsigned entityid)
 | 
			
		||||
{
 | 
			
		||||
  nn_guid_t bwr_guid;
 | 
			
		||||
  ddsi_guid_t bwr_guid;
 | 
			
		||||
  unsigned bes_mask = 0, prismtech_bes_mask = 0;
 | 
			
		||||
 | 
			
		||||
  if (pp->e.onlylocal) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1391,7 +1403,7 @@ static void free_wr_rd_match (struct wr_rd_match *m)
 | 
			
		|||
  if (m) ddsrt_free (m);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void writer_drop_connection (const struct nn_guid *wr_guid, const struct proxy_reader *prd)
 | 
			
		||||
static void writer_drop_connection (const struct ddsi_guid *wr_guid, const struct proxy_reader *prd)
 | 
			
		||||
{
 | 
			
		||||
  struct writer *wr;
 | 
			
		||||
  if ((wr = ephash_lookup_writer_guid (prd->e.gv->guid_hash, wr_guid)) != NULL)
 | 
			
		||||
| 
						 | 
				
			
			@ -1421,7 +1433,7 @@ static void writer_drop_connection (const struct nn_guid *wr_guid, const struct
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void writer_drop_local_connection (const struct nn_guid *wr_guid, struct reader *rd)
 | 
			
		||||
static void writer_drop_local_connection (const struct ddsi_guid *wr_guid, struct reader *rd)
 | 
			
		||||
{
 | 
			
		||||
  /* Only called by gc_delete_reader, so we actually have a reader pointer */
 | 
			
		||||
  struct writer *wr;
 | 
			
		||||
| 
						 | 
				
			
			@ -1448,7 +1460,7 @@ static void writer_drop_local_connection (const struct nn_guid *wr_guid, struct
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void reader_drop_connection (const struct nn_guid *rd_guid, const struct proxy_writer *pwr)
 | 
			
		||||
static void reader_drop_connection (const struct ddsi_guid *rd_guid, const struct proxy_writer *pwr)
 | 
			
		||||
{
 | 
			
		||||
  struct reader *rd;
 | 
			
		||||
  if ((rd = ephash_lookup_reader_guid (pwr->e.gv->guid_hash, rd_guid)) != NULL)
 | 
			
		||||
| 
						 | 
				
			
			@ -1458,31 +1470,33 @@ static void reader_drop_connection (const struct nn_guid *rd_guid, const struct
 | 
			
		|||
    if ((m = ddsrt_avl_lookup (&rd_writers_treedef, &rd->writers, &pwr->e.guid)) != NULL)
 | 
			
		||||
      ddsrt_avl_delete (&rd_writers_treedef, &rd->writers, m);
 | 
			
		||||
    ddsrt_mutex_unlock (&rd->e.lock);
 | 
			
		||||
    if (m != NULL)
 | 
			
		||||
    {
 | 
			
		||||
      if (rd->rhc)
 | 
			
		||||
      {
 | 
			
		||||
        struct ddsi_writer_info wrinfo;
 | 
			
		||||
        ddsi_make_writer_info (&wrinfo, &pwr->e, pwr->c.xqos);
 | 
			
		||||
        ddsi_rhc_unregister_wr (rd->rhc, &wrinfo);
 | 
			
		||||
      }
 | 
			
		||||
      if (rd->status_cb)
 | 
			
		||||
      {
 | 
			
		||||
        status_cb_data_t data;
 | 
			
		||||
 | 
			
		||||
        data.add = false;
 | 
			
		||||
        data.handle = pwr->e.iid;
 | 
			
		||||
 | 
			
		||||
        data.raw_status_id = (int) DDS_LIVELINESS_CHANGED_STATUS_ID;
 | 
			
		||||
        (rd->status_cb) (rd->status_cb_entity, &data);
 | 
			
		||||
 | 
			
		||||
        data.raw_status_id = (int) DDS_SUBSCRIPTION_MATCHED_STATUS_ID;
 | 
			
		||||
        (rd->status_cb) (rd->status_cb_entity, &data);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    free_rd_pwr_match (pwr->e.gv, m);
 | 
			
		||||
 | 
			
		||||
    if (rd->rhc)
 | 
			
		||||
    {
 | 
			
		||||
      struct proxy_writer_info pwr_info;
 | 
			
		||||
      make_proxy_writer_info(&pwr_info, &pwr->e, pwr->c.xqos);
 | 
			
		||||
      rhc_unregister_wr (rd->rhc, &pwr_info);
 | 
			
		||||
    }
 | 
			
		||||
    if (rd->status_cb)
 | 
			
		||||
    {
 | 
			
		||||
      status_cb_data_t data;
 | 
			
		||||
 | 
			
		||||
      data.add = false;
 | 
			
		||||
      data.handle = pwr->e.iid;
 | 
			
		||||
 | 
			
		||||
      data.raw_status_id = (int) DDS_LIVELINESS_CHANGED_STATUS_ID;
 | 
			
		||||
      (rd->status_cb) (rd->status_cb_entity, &data);
 | 
			
		||||
 | 
			
		||||
      data.raw_status_id = (int) DDS_SUBSCRIPTION_MATCHED_STATUS_ID;
 | 
			
		||||
      (rd->status_cb) (rd->status_cb_entity, &data);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void reader_drop_local_connection (const struct nn_guid *rd_guid, const struct writer *wr)
 | 
			
		||||
static void reader_drop_local_connection (const struct ddsi_guid *rd_guid, const struct writer *wr)
 | 
			
		||||
{
 | 
			
		||||
  struct reader *rd;
 | 
			
		||||
  if ((rd = ephash_lookup_reader_guid (wr->e.gv->guid_hash, rd_guid)) != NULL)
 | 
			
		||||
| 
						 | 
				
			
			@ -1492,32 +1506,34 @@ static void reader_drop_local_connection (const struct nn_guid *rd_guid, const s
 | 
			
		|||
    if ((m = ddsrt_avl_lookup (&rd_local_writers_treedef, &rd->local_writers, &wr->e.guid)) != NULL)
 | 
			
		||||
      ddsrt_avl_delete (&rd_local_writers_treedef, &rd->local_writers, m);
 | 
			
		||||
    ddsrt_mutex_unlock (&rd->e.lock);
 | 
			
		||||
    if (m != NULL)
 | 
			
		||||
    {
 | 
			
		||||
      if (rd->rhc)
 | 
			
		||||
      {
 | 
			
		||||
        /* FIXME: */
 | 
			
		||||
        struct ddsi_writer_info wrinfo;
 | 
			
		||||
        ddsi_make_writer_info (&wrinfo, &wr->e, wr->xqos);
 | 
			
		||||
        ddsi_rhc_unregister_wr (rd->rhc, &wrinfo);
 | 
			
		||||
      }
 | 
			
		||||
      if (rd->status_cb)
 | 
			
		||||
      {
 | 
			
		||||
        status_cb_data_t data;
 | 
			
		||||
 | 
			
		||||
        data.add = false;
 | 
			
		||||
        data.handle = wr->e.iid;
 | 
			
		||||
 | 
			
		||||
        data.raw_status_id = (int) DDS_LIVELINESS_CHANGED_STATUS_ID;
 | 
			
		||||
        (rd->status_cb) (rd->status_cb_entity, &data);
 | 
			
		||||
 | 
			
		||||
        data.raw_status_id = (int) DDS_SUBSCRIPTION_MATCHED_STATUS_ID;
 | 
			
		||||
        (rd->status_cb) (rd->status_cb_entity, &data);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    free_rd_wr_match (m);
 | 
			
		||||
 | 
			
		||||
    if (rd->rhc)
 | 
			
		||||
    {
 | 
			
		||||
      /* FIXME: */
 | 
			
		||||
      struct proxy_writer_info pwr_info;
 | 
			
		||||
      make_proxy_writer_info(&pwr_info, &wr->e, wr->xqos);
 | 
			
		||||
      rhc_unregister_wr (rd->rhc, &pwr_info);
 | 
			
		||||
    }
 | 
			
		||||
    if (rd->status_cb)
 | 
			
		||||
    {
 | 
			
		||||
      status_cb_data_t data;
 | 
			
		||||
 | 
			
		||||
      data.add = false;
 | 
			
		||||
      data.handle = wr->e.iid;
 | 
			
		||||
 | 
			
		||||
      data.raw_status_id = (int) DDS_LIVELINESS_CHANGED_STATUS_ID;
 | 
			
		||||
      (rd->status_cb) (rd->status_cb_entity, &data);
 | 
			
		||||
 | 
			
		||||
      data.raw_status_id = (int) DDS_SUBSCRIPTION_MATCHED_STATUS_ID;
 | 
			
		||||
      (rd->status_cb) (rd->status_cb_entity, &data);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void update_reader_init_acknack_count (const ddsrt_log_cfg_t *logcfg, const struct ephash *guid_hash, const struct nn_guid *rd_guid, nn_count_t count)
 | 
			
		||||
static void update_reader_init_acknack_count (const ddsrt_log_cfg_t *logcfg, const struct ephash *guid_hash, const struct ddsi_guid *rd_guid, nn_count_t count)
 | 
			
		||||
{
 | 
			
		||||
  struct reader *rd;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1539,7 +1555,7 @@ static void update_reader_init_acknack_count (const ddsrt_log_cfg_t *logcfg, con
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void proxy_writer_drop_connection (const struct nn_guid *pwr_guid, struct reader *rd)
 | 
			
		||||
static void proxy_writer_drop_connection (const struct ddsi_guid *pwr_guid, struct reader *rd)
 | 
			
		||||
{
 | 
			
		||||
  /* Only called by gc_delete_reader, so we actually have a reader pointer */
 | 
			
		||||
  struct proxy_writer *pwr;
 | 
			
		||||
| 
						 | 
				
			
			@ -1574,7 +1590,7 @@ static void proxy_writer_drop_connection (const struct nn_guid *pwr_guid, struct
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void proxy_reader_drop_connection (const struct nn_guid *prd_guid, struct writer *wr)
 | 
			
		||||
static void proxy_reader_drop_connection (const struct ddsi_guid *prd_guid, struct writer *wr)
 | 
			
		||||
{
 | 
			
		||||
  struct proxy_reader *prd;
 | 
			
		||||
  if ((prd = ephash_lookup_proxy_reader_guid (wr->e.gv->guid_hash, prd_guid)) != NULL)
 | 
			
		||||
| 
						 | 
				
			
			@ -1719,12 +1735,12 @@ static void writer_add_local_connection (struct writer *wr, struct reader *rd)
 | 
			
		|||
    whc_sample_iter_init(wr->whc, &it);
 | 
			
		||||
    while (whc_sample_iter_borrow_next(&it, &sample))
 | 
			
		||||
    {
 | 
			
		||||
      struct proxy_writer_info pwr_info;
 | 
			
		||||
      struct ddsi_writer_info wrinfo;
 | 
			
		||||
      struct ddsi_serdata *payload = sample.serdata;
 | 
			
		||||
      /* FIXME: whc has tk reference in its index nodes, which is what we really should be iterating over anyway, and so we don't really have to look them up anymore */
 | 
			
		||||
      struct ddsi_tkmap_instance *tk = ddsi_tkmap_lookup_instance_ref (tkmap, payload);
 | 
			
		||||
      make_proxy_writer_info (&pwr_info, &wr->e, wr->xqos);
 | 
			
		||||
      (void) rhc_store (rd->rhc, &pwr_info, payload, tk);
 | 
			
		||||
      ddsi_make_writer_info (&wrinfo, &wr->e, wr->xqos);
 | 
			
		||||
      (void) ddsi_rhc_store (rd->rhc, &wrinfo, payload, tk);
 | 
			
		||||
      ddsi_tkmap_instance_unref (tkmap, tk);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -1777,24 +1793,24 @@ static void reader_add_connection (struct reader *rd, struct proxy_writer *pwr,
 | 
			
		|||
    ddsrt_mutex_unlock (&rd->e.lock);
 | 
			
		||||
 | 
			
		||||
#ifdef DDSI_INCLUDE_SSM
 | 
			
		||||
  if (rd->favours_ssm && pwr->supports_ssm)
 | 
			
		||||
  {
 | 
			
		||||
    /* pwr->supports_ssm is set if addrset_contains_ssm(pwr->ssm), so
 | 
			
		||||
    if (rd->favours_ssm && pwr->supports_ssm)
 | 
			
		||||
    {
 | 
			
		||||
      /* pwr->supports_ssm is set if addrset_contains_ssm(pwr->ssm), so
 | 
			
		||||
       any_ssm must succeed. */
 | 
			
		||||
    if (!addrset_any_uc (pwr->c.as, &m->ssm_src_loc))
 | 
			
		||||
      assert (0);
 | 
			
		||||
    if (!addrset_any_ssm (rd->e.gv, pwr->c.as, &m->ssm_mc_loc))
 | 
			
		||||
      assert (0);
 | 
			
		||||
    /* FIXME: for now, assume that the ports match for datasock_mc --
 | 
			
		||||
      if (!addrset_any_uc (pwr->c.as, &m->ssm_src_loc))
 | 
			
		||||
        assert (0);
 | 
			
		||||
      if (!addrset_any_ssm (rd->e.gv, pwr->c.as, &m->ssm_mc_loc))
 | 
			
		||||
        assert (0);
 | 
			
		||||
      /* FIXME: for now, assume that the ports match for datasock_mc --
 | 
			
		||||
       't would be better to dynamically create and destroy sockets on
 | 
			
		||||
       an as needed basis. */
 | 
			
		||||
    ddsi_join_mc (rd->e.gv, rd->e.gv->mship, rd->e.gv->data_conn_mc, &m->ssm_src_loc, &m->ssm_mc_loc);
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
    set_unspec_locator (&m->ssm_src_loc);
 | 
			
		||||
    set_unspec_locator (&m->ssm_mc_loc);
 | 
			
		||||
  }
 | 
			
		||||
      ddsi_join_mc (rd->e.gv, rd->e.gv->mship, rd->e.gv->data_conn_mc, &m->ssm_src_loc, &m->ssm_mc_loc);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
      set_unspec_locator (&m->ssm_src_loc);
 | 
			
		||||
      set_unspec_locator (&m->ssm_mc_loc);
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    if (rd->status_cb)
 | 
			
		||||
| 
						 | 
				
			
			@ -1855,8 +1871,7 @@ static void proxy_writer_add_connection (struct proxy_writer *pwr, struct reader
 | 
			
		|||
  if (ddsrt_avl_lookup_ipath (&pwr_readers_treedef, &pwr->readers, &rd->e.guid, &path))
 | 
			
		||||
    goto already_matched;
 | 
			
		||||
 | 
			
		||||
  if (pwr->c.topic == NULL && rd->topic)
 | 
			
		||||
    pwr->c.topic = ddsi_sertopic_ref (rd->topic);
 | 
			
		||||
  assert (rd->topic || is_builtin_endpoint (rd->e.guid.entityid, NN_VENDORID_ECLIPSE));
 | 
			
		||||
  if (pwr->ddsi2direct_cb == 0 && rd->ddsi2direct_cb != 0)
 | 
			
		||||
  {
 | 
			
		||||
    pwr->ddsi2direct_cb = rd->ddsi2direct_cb;
 | 
			
		||||
| 
						 | 
				
			
			@ -1891,7 +1906,7 @@ static void proxy_writer_add_connection (struct proxy_writer *pwr, struct reader
 | 
			
		|||
    /* builtins really don't care about multiple copies or anything */
 | 
			
		||||
    m->in_sync = PRMSS_SYNC;
 | 
			
		||||
  }
 | 
			
		||||
  else if (!pwr->have_seen_heartbeat)
 | 
			
		||||
  else if (!pwr->have_seen_heartbeat || !rd->handle_as_transient_local)
 | 
			
		||||
  {
 | 
			
		||||
    /* Proxy writer hasn't seen a heartbeat yet: means we have no
 | 
			
		||||
       clue from what sequence number to start accepting data, nor
 | 
			
		||||
| 
						 | 
				
			
			@ -1920,14 +1935,6 @@ static void proxy_writer_add_connection (struct proxy_writer *pwr, struct reader
 | 
			
		|||
      m->in_sync = PRMSS_SYNC;
 | 
			
		||||
    m->u.not_in_sync.end_of_tl_seq = MAX_SEQ_NUMBER;
 | 
			
		||||
  }
 | 
			
		||||
  else if (!rd->handle_as_transient_local)
 | 
			
		||||
  {
 | 
			
		||||
    /* volatile reader, writer has seen a heartbeat: it's in sync
 | 
			
		||||
       (there is a risk of it getting some historical data: that
 | 
			
		||||
       happens to be cached in the writer's reorder admin at this
 | 
			
		||||
       point) */
 | 
			
		||||
    m->in_sync = PRMSS_SYNC;
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
    /* transient-local reader; range of sequence numbers is already
 | 
			
		||||
| 
						 | 
				
			
			@ -1981,7 +1988,6 @@ static void proxy_writer_add_connection (struct proxy_writer *pwr, struct reader
 | 
			
		|||
  return;
 | 
			
		||||
 | 
			
		||||
already_matched:
 | 
			
		||||
  assert (is_builtin_entityid (pwr->e.guid.entityid, pwr->c.vendor) ? (pwr->c.topic == NULL) : (pwr->c.topic != NULL));
 | 
			
		||||
  ELOGDISC (pwr, "  proxy_writer_add_connection(pwr "PGUIDFMT" rd "PGUIDFMT") - already connected\n",
 | 
			
		||||
            PGUID (pwr->e.guid), PGUID (rd->e.guid));
 | 
			
		||||
  ddsrt_mutex_unlock (&pwr->e.lock);
 | 
			
		||||
| 
						 | 
				
			
			@ -1996,8 +2002,6 @@ static void proxy_reader_add_connection (struct proxy_reader *prd, struct writer
 | 
			
		|||
 | 
			
		||||
  m->wr_guid = wr->e.guid;
 | 
			
		||||
  ddsrt_mutex_lock (&prd->e.lock);
 | 
			
		||||
  if (prd->c.topic == NULL)
 | 
			
		||||
    prd->c.topic = ddsi_sertopic_ref (wr->topic);
 | 
			
		||||
  if (ddsrt_avl_lookup_ipath (&prd_writers_treedef, &prd->writers, &wr->e.guid, &path))
 | 
			
		||||
  {
 | 
			
		||||
    ELOGDISC (prd, "  proxy_reader_add_connection(wr "PGUIDFMT" prd "PGUIDFMT") - already connected\n",
 | 
			
		||||
| 
						 | 
				
			
			@ -2007,6 +2011,7 @@ static void proxy_reader_add_connection (struct proxy_reader *prd, struct writer
 | 
			
		|||
  }
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
    assert (wr->topic || is_builtin_endpoint (wr->e.guid.entityid, NN_VENDORID_ECLIPSE));
 | 
			
		||||
    ELOGDISC (prd, "  proxy_reader_add_connection(wr "PGUIDFMT" prd "PGUIDFMT")\n",
 | 
			
		||||
              PGUID (wr->e.guid), PGUID (prd->e.guid));
 | 
			
		||||
    ddsrt_avl_insert_ipath (&prd_writers_treedef, &prd->writers, m, &path);
 | 
			
		||||
| 
						 | 
				
			
			@ -2015,9 +2020,9 @@ static void proxy_reader_add_connection (struct proxy_reader *prd, struct writer
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static nn_entityid_t builtin_entityid_match (nn_entityid_t x)
 | 
			
		||||
static ddsi_entityid_t builtin_entityid_match (ddsi_entityid_t x)
 | 
			
		||||
{
 | 
			
		||||
  nn_entityid_t res;
 | 
			
		||||
  ddsi_entityid_t res;
 | 
			
		||||
  res.u = 0;
 | 
			
		||||
  switch (x.u)
 | 
			
		||||
  {
 | 
			
		||||
| 
						 | 
				
			
			@ -2164,7 +2169,7 @@ static void connect_proxy_writer_with_reader (struct proxy_writer *pwr, struct r
 | 
			
		|||
  proxy_writer_add_connection (pwr, rd, tnow, init_count);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool ignore_local_p (const nn_guid_t *guid1, const nn_guid_t *guid2, const struct dds_qos *xqos1, const struct dds_qos *xqos2)
 | 
			
		||||
static bool ignore_local_p (const ddsi_guid_t *guid1, const ddsi_guid_t *guid2, const struct dds_qos *xqos1, const struct dds_qos *xqos2)
 | 
			
		||||
{
 | 
			
		||||
  assert (xqos1->present & QP_CYCLONE_IGNORELOCAL);
 | 
			
		||||
  assert (xqos2->present & QP_CYCLONE_IGNORELOCAL);
 | 
			
		||||
| 
						 | 
				
			
			@ -2383,7 +2388,7 @@ static void generic_do_match (struct entity_common *e, nn_mtime_t tnow)
 | 
			
		|||
  else
 | 
			
		||||
  {
 | 
			
		||||
    /* Built-ins have fixed QoS */
 | 
			
		||||
    nn_entityid_t tgt_ent = builtin_entityid_match (e->guid.entityid);
 | 
			
		||||
    ddsi_entityid_t tgt_ent = builtin_entityid_match (e->guid.entityid);
 | 
			
		||||
    enum entity_kind pkind = generic_do_match_isproxy (e) ? EK_PARTICIPANT : EK_PROXY_PARTICIPANT;
 | 
			
		||||
    EELOGDISC (e, "match_%s_with_%ss(%s "PGUIDFMT") scanning %sparticipants tgt=%"PRIx32"\n",
 | 
			
		||||
               generic_do_match_kindstr_us (e->kind), generic_do_match_kindstr_us (mkind),
 | 
			
		||||
| 
						 | 
				
			
			@ -2396,7 +2401,7 @@ static void generic_do_match (struct entity_common *e, nn_mtime_t tnow)
 | 
			
		|||
      ephash_enum_init (&est, guid_hash, pkind);
 | 
			
		||||
      while ((ep = ephash_enum_next (&est)) != NULL)
 | 
			
		||||
      {
 | 
			
		||||
        nn_guid_t tgt_guid;
 | 
			
		||||
        ddsi_guid_t tgt_guid;
 | 
			
		||||
        tgt_guid.prefix = ep->guid.prefix;
 | 
			
		||||
        tgt_guid.entityid = tgt_ent;
 | 
			
		||||
        if ((em = ephash_lookup_guid (guid_hash, &tgt_guid, mkind)) != NULL)
 | 
			
		||||
| 
						 | 
				
			
			@ -2463,7 +2468,7 @@ static void match_proxy_reader_with_writers (struct proxy_reader *prd, nn_mtime_
 | 
			
		|||
 | 
			
		||||
/* ENDPOINT --------------------------------------------------------- */
 | 
			
		||||
 | 
			
		||||
static void new_reader_writer_common (const struct ddsrt_log_cfg *logcfg, const struct nn_guid *guid, const struct ddsi_sertopic *topic, const struct dds_qos *xqos)
 | 
			
		||||
static void new_reader_writer_common (const struct ddsrt_log_cfg *logcfg, const struct ddsi_guid *guid, const struct ddsi_sertopic *topic, const struct dds_qos *xqos)
 | 
			
		||||
{
 | 
			
		||||
  const char *partition = "(default)";
 | 
			
		||||
  const char *partition_suffix = "";
 | 
			
		||||
| 
						 | 
				
			
			@ -2489,7 +2494,7 @@ static void new_reader_writer_common (const struct ddsrt_log_cfg *logcfg, const
 | 
			
		|||
            topic ? topic->type_name : "(null)");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void endpoint_common_init (struct entity_common *e, struct endpoint_common *c, struct q_globals *gv, enum entity_kind kind, const struct nn_guid *guid, const struct nn_guid *group_guid, struct participant *pp, bool onlylocal)
 | 
			
		||||
static void endpoint_common_init (struct entity_common *e, struct endpoint_common *c, struct q_globals *gv, enum entity_kind kind, const struct ddsi_guid *guid, const struct ddsi_guid *group_guid, struct participant *pp, bool onlylocal)
 | 
			
		||||
{
 | 
			
		||||
  entity_common_init (e, gv, guid, NULL, kind, now (), NN_VENDORID_ECLIPSE, pp->e.onlylocal || onlylocal);
 | 
			
		||||
  c->pp = ref_participant (pp, &e->guid);
 | 
			
		||||
| 
						 | 
				
			
			@ -2878,7 +2883,7 @@ static void new_writer_guid_common_init (struct writer *wr, const struct ddsi_se
 | 
			
		|||
  local_reader_ary_init (&wr->rdary);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static dds_return_t new_writer_guid (struct writer **wr_out, const struct nn_guid *guid, const struct nn_guid *group_guid, struct participant *pp, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct whc *whc, status_cb_t status_cb, void *status_entity)
 | 
			
		||||
static dds_return_t new_writer_guid (struct writer **wr_out, const struct ddsi_guid *guid, const struct ddsi_guid *group_guid, struct participant *pp, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct whc *whc, status_cb_t status_cb, void *status_entity)
 | 
			
		||||
{
 | 
			
		||||
  struct writer *wr;
 | 
			
		||||
  nn_mtime_t tnow = now_mt ();
 | 
			
		||||
| 
						 | 
				
			
			@ -2929,7 +2934,7 @@ static dds_return_t new_writer_guid (struct writer **wr_out, const struct nn_gui
 | 
			
		|||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dds_return_t new_writer (struct writer **wr_out, struct q_globals *gv, struct nn_guid *wrguid, const struct nn_guid *group_guid, const struct nn_guid *ppguid, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct whc * whc, status_cb_t status_cb, void *status_cb_arg)
 | 
			
		||||
dds_return_t new_writer (struct writer **wr_out, struct q_globals *gv, struct ddsi_guid *wrguid, const struct ddsi_guid *group_guid, const struct ddsi_guid *ppguid, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct whc * whc, status_cb_t status_cb, void *status_cb_arg)
 | 
			
		||||
{
 | 
			
		||||
  struct participant *pp;
 | 
			
		||||
  dds_return_t rc;
 | 
			
		||||
| 
						 | 
				
			
			@ -2951,9 +2956,9 @@ dds_return_t new_writer (struct writer **wr_out, struct q_globals *gv, struct nn
 | 
			
		|||
  return new_writer_guid (wr_out, wrguid, group_guid, pp, topic, xqos, whc, status_cb, status_cb_arg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct local_orphan_writer *new_local_orphan_writer (struct q_globals *gv, nn_entityid_t entityid, struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct whc *whc)
 | 
			
		||||
struct local_orphan_writer *new_local_orphan_writer (struct q_globals *gv, ddsi_entityid_t entityid, struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct whc *whc)
 | 
			
		||||
{
 | 
			
		||||
  nn_guid_t guid;
 | 
			
		||||
  ddsi_guid_t guid;
 | 
			
		||||
  struct local_orphan_writer *lowr;
 | 
			
		||||
  struct writer *wr;
 | 
			
		||||
  nn_mtime_t tnow = now_mt ();
 | 
			
		||||
| 
						 | 
				
			
			@ -3072,6 +3077,22 @@ static void writer_set_state (struct writer *wr, enum writer_state newstate)
 | 
			
		|||
  wr->state = newstate;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dds_return_t unblock_throttled_writer (struct q_globals *gv, const struct ddsi_guid *guid)
 | 
			
		||||
{
 | 
			
		||||
  struct writer *wr;
 | 
			
		||||
  assert (is_writer_entityid (guid->entityid));
 | 
			
		||||
  if ((wr = ephash_lookup_writer_guid (gv->guid_hash, guid)) == NULL)
 | 
			
		||||
  {
 | 
			
		||||
    GVLOGDISC ("unblock_throttled_writer(guid "PGUIDFMT") - unknown guid\n", PGUID (*guid));
 | 
			
		||||
    return DDS_RETCODE_BAD_PARAMETER;
 | 
			
		||||
  }
 | 
			
		||||
  GVLOGDISC ("unblock_throttled_writer(guid "PGUIDFMT") ...\n", PGUID (*guid));
 | 
			
		||||
  ddsrt_mutex_lock (&wr->e.lock);
 | 
			
		||||
  writer_set_state (wr, WRST_INTERRUPT);
 | 
			
		||||
  ddsrt_mutex_unlock (&wr->e.lock);
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dds_return_t delete_writer_nolinger_locked (struct writer *wr)
 | 
			
		||||
{
 | 
			
		||||
  ELOGDISC (wr, "delete_writer_nolinger(guid "PGUIDFMT") ...\n", PGUID (wr->e.guid));
 | 
			
		||||
| 
						 | 
				
			
			@ -3084,7 +3105,7 @@ dds_return_t delete_writer_nolinger_locked (struct writer *wr)
 | 
			
		|||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dds_return_t delete_writer_nolinger (struct q_globals *gv, const struct nn_guid *guid)
 | 
			
		||||
dds_return_t delete_writer_nolinger (struct q_globals *gv, const struct ddsi_guid *guid)
 | 
			
		||||
{
 | 
			
		||||
  struct writer *wr;
 | 
			
		||||
  /* We take no care to ensure application writers are not deleted
 | 
			
		||||
| 
						 | 
				
			
			@ -3108,12 +3129,13 @@ dds_return_t delete_writer_nolinger (struct q_globals *gv, const struct nn_guid
 | 
			
		|||
 | 
			
		||||
void delete_local_orphan_writer (struct local_orphan_writer *lowr)
 | 
			
		||||
{
 | 
			
		||||
  assert (thread_is_awake ());
 | 
			
		||||
  ddsrt_mutex_lock (&lowr->wr.e.lock);
 | 
			
		||||
  delete_writer_nolinger_locked (&lowr->wr);
 | 
			
		||||
  ddsrt_mutex_unlock (&lowr->wr.e.lock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dds_return_t delete_writer (struct q_globals *gv, const struct nn_guid *guid)
 | 
			
		||||
dds_return_t delete_writer (struct q_globals *gv, const struct ddsi_guid *guid)
 | 
			
		||||
{
 | 
			
		||||
  struct writer *wr;
 | 
			
		||||
  struct whc_state whcst;
 | 
			
		||||
| 
						 | 
				
			
			@ -3261,12 +3283,12 @@ static void leave_mcast_helper (const nn_locator_t *n, void *varg)
 | 
			
		|||
static dds_return_t new_reader_guid
 | 
			
		||||
(
 | 
			
		||||
  struct reader **rd_out,
 | 
			
		||||
  const struct nn_guid *guid,
 | 
			
		||||
  const struct nn_guid *group_guid,
 | 
			
		||||
  const struct ddsi_guid *guid,
 | 
			
		||||
  const struct ddsi_guid *group_guid,
 | 
			
		||||
  struct participant *pp,
 | 
			
		||||
  const struct ddsi_sertopic *topic,
 | 
			
		||||
  const struct dds_qos *xqos,
 | 
			
		||||
  struct rhc *rhc,
 | 
			
		||||
  struct ddsi_rhc *rhc,
 | 
			
		||||
  status_cb_t status_cb,
 | 
			
		||||
  void * status_entity
 | 
			
		||||
)
 | 
			
		||||
| 
						 | 
				
			
			@ -3322,7 +3344,7 @@ static dds_return_t new_reader_guid
 | 
			
		|||
  /* set rhc qos for reader */
 | 
			
		||||
  if (rhc)
 | 
			
		||||
  {
 | 
			
		||||
    rhc_set_qos (rd->rhc, rd->xqos);
 | 
			
		||||
    ddsi_rhc_set_qos (rd->rhc, rd->xqos);
 | 
			
		||||
  }
 | 
			
		||||
  assert (rd->xqos->present & QP_LIVELINESS);
 | 
			
		||||
  if (rd->xqos->liveliness.kind != DDS_LIVELINESS_AUTOMATIC || rd->xqos->liveliness.lease_duration != T_NEVER)
 | 
			
		||||
| 
						 | 
				
			
			@ -3403,12 +3425,12 @@ dds_return_t new_reader
 | 
			
		|||
(
 | 
			
		||||
  struct reader **rd_out,
 | 
			
		||||
  struct q_globals *gv,
 | 
			
		||||
  struct nn_guid *rdguid,
 | 
			
		||||
  const struct nn_guid *group_guid,
 | 
			
		||||
  const struct nn_guid *ppguid,
 | 
			
		||||
  struct ddsi_guid *rdguid,
 | 
			
		||||
  const struct ddsi_guid *group_guid,
 | 
			
		||||
  const struct ddsi_guid *ppguid,
 | 
			
		||||
  const struct ddsi_sertopic *topic,
 | 
			
		||||
  const struct dds_qos *xqos,
 | 
			
		||||
  struct rhc * rhc,
 | 
			
		||||
  struct ddsi_rhc * rhc,
 | 
			
		||||
  status_cb_t status_cb,
 | 
			
		||||
  void * status_cbarg
 | 
			
		||||
)
 | 
			
		||||
| 
						 | 
				
			
			@ -3461,9 +3483,9 @@ static void gc_delete_reader (struct gcreq *gcreq)
 | 
			
		|||
    addrset_forall (rd->as, leave_mcast_helper, &arg);
 | 
			
		||||
  }
 | 
			
		||||
#endif
 | 
			
		||||
  if (rd->rhc)
 | 
			
		||||
  if (rd->rhc && is_builtin_entityid (rd->e.guid.entityid, NN_VENDORID_ECLIPSE))
 | 
			
		||||
  {
 | 
			
		||||
    rhc_free (rd->rhc);
 | 
			
		||||
    ddsi_rhc_free (rd->rhc);
 | 
			
		||||
  }
 | 
			
		||||
  if (rd->status_cb)
 | 
			
		||||
  {
 | 
			
		||||
| 
						 | 
				
			
			@ -3481,7 +3503,7 @@ static void gc_delete_reader (struct gcreq *gcreq)
 | 
			
		|||
  ddsrt_free (rd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dds_return_t delete_reader (struct q_globals *gv, const struct nn_guid *guid)
 | 
			
		||||
dds_return_t delete_reader (struct q_globals *gv, const struct ddsi_guid *guid)
 | 
			
		||||
{
 | 
			
		||||
  struct reader *rd;
 | 
			
		||||
  assert (!is_writer_entityid (guid->entityid));
 | 
			
		||||
| 
						 | 
				
			
			@ -3544,10 +3566,10 @@ void proxy_participant_reassign_lease (struct proxy_participant *proxypp, struct
 | 
			
		|||
void new_proxy_participant
 | 
			
		||||
(
 | 
			
		||||
  struct q_globals *gv,
 | 
			
		||||
  const struct nn_guid *ppguid,
 | 
			
		||||
  const struct ddsi_guid *ppguid,
 | 
			
		||||
  unsigned bes,
 | 
			
		||||
  unsigned prismtech_bes,
 | 
			
		||||
  const struct nn_guid *privileged_pp_guid,
 | 
			
		||||
  const struct ddsi_guid *privileged_pp_guid,
 | 
			
		||||
  struct addrset *as_default,
 | 
			
		||||
  struct addrset *as_meta,
 | 
			
		||||
  const nn_plist_t *plist,
 | 
			
		||||
| 
						 | 
				
			
			@ -3696,7 +3718,7 @@ void new_proxy_participant
 | 
			
		|||
      const struct bestab *te = &bestab[i];
 | 
			
		||||
      if ((proxypp->bes & te->besflag) || (proxypp->prismtech_bes & te->prismtech_besflag))
 | 
			
		||||
      {
 | 
			
		||||
        nn_guid_t guid1;
 | 
			
		||||
        ddsi_guid_t guid1;
 | 
			
		||||
        guid1.prefix = proxypp->e.guid.prefix;
 | 
			
		||||
        guid1.entityid.u = te->entityid;
 | 
			
		||||
        assert (is_builtin_entityid (guid1.entityid, proxypp->vendor));
 | 
			
		||||
| 
						 | 
				
			
			@ -3815,7 +3837,7 @@ static void unref_proxy_participant (struct proxy_participant *proxypp, struct p
 | 
			
		|||
    if (proxypp->owns_lease)
 | 
			
		||||
      lease_free (ddsrt_atomic_ldvoidp (&proxypp->lease));
 | 
			
		||||
    entity_common_fini (&proxypp->e);
 | 
			
		||||
    remove_deleted_participant_guid (&proxypp->e.gv->logconfig, proxypp->e.gv->deleted_participants, &proxypp->e.guid, DPG_LOCAL | DPG_REMOTE);
 | 
			
		||||
    remove_deleted_participant_guid (proxypp->e.gv->deleted_participants, &proxypp->e.guid, DPG_LOCAL | DPG_REMOTE);
 | 
			
		||||
    ddsrt_free (proxypp);
 | 
			
		||||
  }
 | 
			
		||||
  else if (proxypp->endpoints == NULL && proxypp->implicitly_created)
 | 
			
		||||
| 
						 | 
				
			
			@ -3959,7 +3981,7 @@ void purge_proxy_participants (struct q_globals *gv, const nn_locator_t *loc, bo
 | 
			
		|||
  thread_state_asleep (ts1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int delete_proxy_participant_by_guid (struct q_globals *gv, const struct nn_guid *guid, nn_wctime_t timestamp, int isimplicit)
 | 
			
		||||
int delete_proxy_participant_by_guid (struct q_globals *gv, const struct ddsi_guid *guid, nn_wctime_t timestamp, int isimplicit)
 | 
			
		||||
{
 | 
			
		||||
  struct proxy_participant *ppt;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3982,7 +4004,7 @@ int delete_proxy_participant_by_guid (struct q_globals *gv, const struct nn_guid
 | 
			
		|||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint64_t get_entity_instance_id (const struct q_globals *gv, const struct nn_guid *guid)
 | 
			
		||||
uint64_t get_entity_instance_id (const struct q_globals *gv, const struct ddsi_guid *guid)
 | 
			
		||||
{
 | 
			
		||||
  struct thread_state1 *ts1 = lookup_thread_state ();
 | 
			
		||||
  struct entity_common *e;
 | 
			
		||||
| 
						 | 
				
			
			@ -3996,7 +4018,7 @@ uint64_t get_entity_instance_id (const struct q_globals *gv, const struct nn_gui
 | 
			
		|||
 | 
			
		||||
/* PROXY-ENDPOINT --------------------------------------------------- */
 | 
			
		||||
 | 
			
		||||
static void proxy_endpoint_common_init (struct entity_common *e, struct proxy_endpoint_common *c, enum entity_kind kind, const struct nn_guid *guid, nn_wctime_t tcreate, seqno_t seq, struct proxy_participant *proxypp, struct addrset *as, const nn_plist_t *plist)
 | 
			
		||||
static void proxy_endpoint_common_init (struct entity_common *e, struct proxy_endpoint_common *c, enum entity_kind kind, const struct ddsi_guid *guid, nn_wctime_t tcreate, seqno_t seq, struct proxy_participant *proxypp, struct addrset *as, const nn_plist_t *plist)
 | 
			
		||||
{
 | 
			
		||||
  const char *name;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -4009,7 +4031,6 @@ static void proxy_endpoint_common_init (struct entity_common *e, struct proxy_en
 | 
			
		|||
  entity_common_init (e, proxypp->e.gv, guid, name, kind, tcreate, proxypp->vendor, false);
 | 
			
		||||
  c->xqos = nn_xqos_dup (&plist->qos);
 | 
			
		||||
  c->as = ref_addrset (as);
 | 
			
		||||
  c->topic = NULL; /* set from first matching reader/writer */
 | 
			
		||||
  c->vendor = proxypp->vendor;
 | 
			
		||||
  c->seq = seq;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -4024,18 +4045,15 @@ static void proxy_endpoint_common_init (struct entity_common *e, struct proxy_en
 | 
			
		|||
static void proxy_endpoint_common_fini (struct entity_common *e, struct proxy_endpoint_common *c)
 | 
			
		||||
{
 | 
			
		||||
  unref_proxy_participant (c->proxypp, c);
 | 
			
		||||
 | 
			
		||||
  ddsi_sertopic_unref (c->topic);
 | 
			
		||||
  nn_xqos_fini (c->xqos);
 | 
			
		||||
  ddsrt_free (c->xqos);
 | 
			
		||||
  unref_addrset (c->as);
 | 
			
		||||
 | 
			
		||||
  entity_common_fini (e);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* PROXY-WRITER ----------------------------------------------------- */
 | 
			
		||||
 | 
			
		||||
int new_proxy_writer (struct q_globals *gv, const struct nn_guid *ppguid, const struct nn_guid *guid, struct addrset *as, const nn_plist_t *plist, struct nn_dqueue *dqueue, struct xeventq *evq, nn_wctime_t timestamp, seqno_t seq)
 | 
			
		||||
int new_proxy_writer (struct q_globals *gv, const struct ddsi_guid *ppguid, const struct ddsi_guid *guid, struct addrset *as, const nn_plist_t *plist, struct nn_dqueue *dqueue, struct xeventq *evq, nn_wctime_t timestamp, seqno_t seq)
 | 
			
		||||
{
 | 
			
		||||
  struct proxy_participant *proxypp;
 | 
			
		||||
  struct proxy_writer *pwr;
 | 
			
		||||
| 
						 | 
				
			
			@ -4168,7 +4186,7 @@ void update_proxy_writer (struct proxy_writer *pwr, seqno_t seq, struct addrset
 | 
			
		|||
void update_proxy_reader (struct proxy_reader *prd, seqno_t seq, struct addrset *as, const struct dds_qos *xqos, nn_wctime_t timestamp)
 | 
			
		||||
{
 | 
			
		||||
  struct prd_wr_match * m;
 | 
			
		||||
  nn_guid_t wrguid;
 | 
			
		||||
  ddsi_guid_t wrguid;
 | 
			
		||||
 | 
			
		||||
  memset (&wrguid, 0, sizeof (wrguid));
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -4185,11 +4203,11 @@ void update_proxy_reader (struct proxy_reader *prd, seqno_t seq, struct addrset
 | 
			
		|||
      prd->c.as = as;
 | 
			
		||||
 | 
			
		||||
      /* Rebuild writer endpoints */
 | 
			
		||||
      
 | 
			
		||||
 | 
			
		||||
      while ((m = ddsrt_avl_lookup_succ_eq (&prd_writers_treedef, &prd->writers, &wrguid)) != NULL)
 | 
			
		||||
      {
 | 
			
		||||
        struct prd_wr_match *next;
 | 
			
		||||
        nn_guid_t guid_next;
 | 
			
		||||
        ddsi_guid_t guid_next;
 | 
			
		||||
        struct writer * wr;
 | 
			
		||||
 | 
			
		||||
        wrguid = m->wr_guid;
 | 
			
		||||
| 
						 | 
				
			
			@ -4244,7 +4262,7 @@ static void gc_delete_proxy_writer (struct gcreq *gcreq)
 | 
			
		|||
  ddsrt_free (pwr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int delete_proxy_writer (struct q_globals *gv, const struct nn_guid *guid, nn_wctime_t timestamp, int isimplicit)
 | 
			
		||||
int delete_proxy_writer (struct q_globals *gv, const struct ddsi_guid *guid, nn_wctime_t timestamp, int isimplicit)
 | 
			
		||||
{
 | 
			
		||||
  struct proxy_writer *pwr;
 | 
			
		||||
  (void)isimplicit;
 | 
			
		||||
| 
						 | 
				
			
			@ -4271,7 +4289,7 @@ int delete_proxy_writer (struct q_globals *gv, const struct nn_guid *guid, nn_wc
 | 
			
		|||
 | 
			
		||||
/* PROXY-READER ----------------------------------------------------- */
 | 
			
		||||
 | 
			
		||||
int new_proxy_reader (struct q_globals *gv, const struct nn_guid *ppguid, const struct nn_guid *guid, struct addrset *as, const nn_plist_t *plist, nn_wctime_t timestamp, seqno_t seq
 | 
			
		||||
int new_proxy_reader (struct q_globals *gv, const struct ddsi_guid *ppguid, const struct ddsi_guid *guid, struct addrset *as, const nn_plist_t *plist, nn_wctime_t timestamp, seqno_t seq
 | 
			
		||||
#ifdef DDSI_INCLUDE_SSM
 | 
			
		||||
                      , int favours_ssm
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -4313,7 +4331,7 @@ int new_proxy_reader (struct q_globals *gv, const struct nn_guid *ppguid, const
 | 
			
		|||
 | 
			
		||||
static void proxy_reader_set_delete_and_ack_all_messages (struct proxy_reader *prd)
 | 
			
		||||
{
 | 
			
		||||
  nn_guid_t wrguid;
 | 
			
		||||
  ddsi_guid_t wrguid;
 | 
			
		||||
  struct writer *wr;
 | 
			
		||||
  struct prd_wr_match *m;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -4325,7 +4343,7 @@ static void proxy_reader_set_delete_and_ack_all_messages (struct proxy_reader *p
 | 
			
		|||
    /* have to be careful walking the tree -- pretty is different, but
 | 
			
		||||
       I want to check this before I write a lookup_succ function. */
 | 
			
		||||
    struct prd_wr_match *m_a_next;
 | 
			
		||||
    nn_guid_t wrguid_next;
 | 
			
		||||
    ddsi_guid_t wrguid_next;
 | 
			
		||||
    wrguid = m->wr_guid;
 | 
			
		||||
    if ((m_a_next = ddsrt_avl_find_succ (&prd_writers_treedef, &prd->writers, m)) != NULL)
 | 
			
		||||
      wrguid_next = m_a_next->wr_guid;
 | 
			
		||||
| 
						 | 
				
			
			@ -4377,7 +4395,7 @@ static void gc_delete_proxy_reader (struct gcreq *gcreq)
 | 
			
		|||
  ddsrt_free (prd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int delete_proxy_reader (struct q_globals *gv, const struct nn_guid *guid, nn_wctime_t timestamp, int isimplicit)
 | 
			
		||||
int delete_proxy_reader (struct q_globals *gv, const struct ddsi_guid *guid, nn_wctime_t timestamp, int isimplicit)
 | 
			
		||||
{
 | 
			
		||||
  struct proxy_reader *prd;
 | 
			
		||||
  (void)isimplicit;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -113,7 +113,7 @@ static void ephash_guid_remove (struct ephash *gh, struct entity_common *e)
 | 
			
		|||
  assert (x);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void *ephash_lookup_guid_untyped (const struct ephash *gh, const struct nn_guid *guid)
 | 
			
		||||
void *ephash_lookup_guid_untyped (const struct ephash *gh, const struct ddsi_guid *guid)
 | 
			
		||||
{
 | 
			
		||||
  /* FIXME: could (now) require guid to be first in entity_common; entity_common already is first in entity */
 | 
			
		||||
  struct entity_common e;
 | 
			
		||||
| 
						 | 
				
			
			@ -122,7 +122,7 @@ void *ephash_lookup_guid_untyped (const struct ephash *gh, const struct nn_guid
 | 
			
		|||
  return ddsrt_chh_lookup (gh->hash, &e);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void *ephash_lookup_guid_int (const struct ephash *gh, const struct nn_guid *guid, enum entity_kind kind)
 | 
			
		||||
static void *ephash_lookup_guid_int (const struct ephash *gh, const struct ddsi_guid *guid, enum entity_kind kind)
 | 
			
		||||
{
 | 
			
		||||
  struct entity_common *res;
 | 
			
		||||
  if ((res = ephash_lookup_guid_untyped (gh, guid)) != NULL && res->kind == kind)
 | 
			
		||||
| 
						 | 
				
			
			@ -131,7 +131,7 @@ static void *ephash_lookup_guid_int (const struct ephash *gh, const struct nn_gu
 | 
			
		|||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void *ephash_lookup_guid (const struct ephash *gh, const struct nn_guid *guid, enum entity_kind kind)
 | 
			
		||||
void *ephash_lookup_guid (const struct ephash *gh, const struct ddsi_guid *guid, enum entity_kind kind)
 | 
			
		||||
{
 | 
			
		||||
  return ephash_lookup_guid_int (gh, guid, kind);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -196,42 +196,42 @@ void ephash_remove_proxy_reader_guid (struct ephash *gh, struct proxy_reader *pr
 | 
			
		|||
  ephash_guid_remove (gh, &prd->e);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct participant *ephash_lookup_participant_guid (const struct ephash *gh, const struct nn_guid *guid)
 | 
			
		||||
struct participant *ephash_lookup_participant_guid (const struct ephash *gh, const struct ddsi_guid *guid)
 | 
			
		||||
{
 | 
			
		||||
  assert (guid->entityid.u == NN_ENTITYID_PARTICIPANT);
 | 
			
		||||
  assert (offsetof (struct participant, e) == 0);
 | 
			
		||||
  return ephash_lookup_guid_int (gh, guid, EK_PARTICIPANT);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct proxy_participant *ephash_lookup_proxy_participant_guid (const struct ephash *gh, const struct nn_guid *guid)
 | 
			
		||||
struct proxy_participant *ephash_lookup_proxy_participant_guid (const struct ephash *gh, const struct ddsi_guid *guid)
 | 
			
		||||
{
 | 
			
		||||
  assert (guid->entityid.u == NN_ENTITYID_PARTICIPANT);
 | 
			
		||||
  assert (offsetof (struct proxy_participant, e) == 0);
 | 
			
		||||
  return ephash_lookup_guid_int (gh, guid, EK_PROXY_PARTICIPANT);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct writer *ephash_lookup_writer_guid (const struct ephash *gh, const struct nn_guid *guid)
 | 
			
		||||
struct writer *ephash_lookup_writer_guid (const struct ephash *gh, const struct ddsi_guid *guid)
 | 
			
		||||
{
 | 
			
		||||
  assert (is_writer_entityid (guid->entityid));
 | 
			
		||||
  assert (offsetof (struct writer, e) == 0);
 | 
			
		||||
  return ephash_lookup_guid_int (gh, guid, EK_WRITER);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct reader *ephash_lookup_reader_guid (const struct ephash *gh, const struct nn_guid *guid)
 | 
			
		||||
struct reader *ephash_lookup_reader_guid (const struct ephash *gh, const struct ddsi_guid *guid)
 | 
			
		||||
{
 | 
			
		||||
  assert (is_reader_entityid (guid->entityid));
 | 
			
		||||
  assert (offsetof (struct reader, e) == 0);
 | 
			
		||||
  return ephash_lookup_guid_int (gh, guid, EK_READER);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct proxy_writer *ephash_lookup_proxy_writer_guid (const struct ephash *gh, const struct nn_guid *guid)
 | 
			
		||||
struct proxy_writer *ephash_lookup_proxy_writer_guid (const struct ephash *gh, const struct ddsi_guid *guid)
 | 
			
		||||
{
 | 
			
		||||
  assert (is_writer_entityid (guid->entityid));
 | 
			
		||||
  assert (offsetof (struct proxy_writer, e) == 0);
 | 
			
		||||
  return ephash_lookup_guid_int (gh, guid, EK_PROXY_WRITER);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct proxy_reader *ephash_lookup_proxy_reader_guid (const struct ephash *gh, const struct nn_guid *guid)
 | 
			
		||||
struct proxy_reader *ephash_lookup_proxy_reader_guid (const struct ephash *gh, const struct ddsi_guid *guid)
 | 
			
		||||
{
 | 
			
		||||
  assert (is_reader_entityid (guid->entityid));
 | 
			
		||||
  assert (offsetof (struct proxy_reader, e) == 0);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -949,7 +949,7 @@ int rtps_init (struct q_globals *gv)
 | 
			
		|||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  assert ((gv->config.allowMulticast & AMC_DEFAULT) == 0);
 | 
			
		||||
  if (set_recvips (gv) < 0)
 | 
			
		||||
    goto err_set_recvips;
 | 
			
		||||
| 
						 | 
				
			
			@ -1027,17 +1027,45 @@ int rtps_init (struct q_globals *gv)
 | 
			
		|||
  ddsrt_mutex_init (&gv->participant_set_lock);
 | 
			
		||||
  ddsrt_cond_init (&gv->participant_set_cond);
 | 
			
		||||
  lease_management_init (gv);
 | 
			
		||||
  gv->deleted_participants = deleted_participants_admin_new (gv->config.prune_deleted_ppant.delay);
 | 
			
		||||
  gv->deleted_participants = deleted_participants_admin_new (&gv->logconfig, gv->config.prune_deleted_ppant.delay);
 | 
			
		||||
  gv->guid_hash = ephash_new (gv);
 | 
			
		||||
 | 
			
		||||
  ddsrt_mutex_init (&gv->privileged_pp_lock);
 | 
			
		||||
  gv->privileged_pp = NULL;
 | 
			
		||||
 | 
			
		||||
  /* Template PP guid -- protected by privileged_pp_lock for simplicity */
 | 
			
		||||
  gv->next_ppguid.prefix.u[0] = locator_to_hopefully_unique_uint32 (&gv->ownloc);
 | 
			
		||||
  gv->next_ppguid.prefix.u[1] = (unsigned) ddsrt_getpid ();
 | 
			
		||||
  gv->next_ppguid.prefix.u[2] = 1;
 | 
			
		||||
  gv->next_ppguid.entityid.u = NN_ENTITYID_PARTICIPANT;
 | 
			
		||||
  /* Base participant GUID.  IID initialisation should be from a really good random
 | 
			
		||||
     generator and yield almost-unique numbers, and with a fallback of using process
 | 
			
		||||
     id, timestamp and a counter, so incorporating that should do a lot to construct
 | 
			
		||||
     a pseudo-random ID.  (The assumption here is that feeding pseudo-random data in
 | 
			
		||||
     MD5 will not change the randomness ...)  Mix in the network configuration to
 | 
			
		||||
     make machines with very reproducible boot sequences and low-resolution clocks
 | 
			
		||||
     distinguishable.
 | 
			
		||||
 | 
			
		||||
     This base is kept constant, prefix.u[1] and prefix.u[2] are then treated as a
 | 
			
		||||
     64-bit unsigned integer to which we add IIDs to generate a hopping sequence
 | 
			
		||||
     that won't repeat in the lifetime of the process.  Seems like it ought to work
 | 
			
		||||
     to keep the risks of collisions low. */
 | 
			
		||||
  {
 | 
			
		||||
    uint64_t iid = toBE8u (ddsi_iid_gen ());
 | 
			
		||||
    ddsrt_md5_state_t st;
 | 
			
		||||
    ddsrt_md5_byte_t digest[16];
 | 
			
		||||
    ddsrt_md5_init (&st);
 | 
			
		||||
    ddsrt_md5_append (&st, (const ddsrt_md5_byte_t *) &iid, sizeof (iid));
 | 
			
		||||
    for (int i = 0; i < gv->n_interfaces; i++)
 | 
			
		||||
    {
 | 
			
		||||
      const struct nn_interface *intf = &gv->interfaces[i];
 | 
			
		||||
      ddsrt_md5_append (&st, (const ddsrt_md5_byte_t *) &intf->loc.kind, sizeof (intf->loc.kind));
 | 
			
		||||
      ddsrt_md5_append (&st, (const ddsrt_md5_byte_t *) intf->loc.address, sizeof (intf->loc.address));
 | 
			
		||||
    }
 | 
			
		||||
    ddsrt_md5_finish (&st, digest);
 | 
			
		||||
    /* DDSI 2.2 requires the first two bytes of the GUID to be set to the vendor
 | 
			
		||||
       code -- a terrible waste of entropy ... */
 | 
			
		||||
    gv->ppguid_base.prefix.s[0] = NN_VENDORID_ECLIPSE.id[0];
 | 
			
		||||
    gv->ppguid_base.prefix.s[1] = NN_VENDORID_ECLIPSE.id[1];
 | 
			
		||||
    DDSRT_STATIC_ASSERT (sizeof (gv->ppguid_base.prefix.s) > 2 && sizeof (gv->ppguid_base.prefix.s) - 2 <= sizeof (digest));
 | 
			
		||||
    memcpy (&gv->ppguid_base.prefix.s[2], digest, sizeof (gv->ppguid_base.prefix.s) - 2);
 | 
			
		||||
    gv->ppguid_base.entityid.u = NN_ENTITYID_PARTICIPANT;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ddsrt_mutex_init (&gv->lock);
 | 
			
		||||
  ddsrt_mutex_init (&gv->spdp_lock);
 | 
			
		||||
| 
						 | 
				
			
			@ -1107,7 +1135,7 @@ int rtps_init (struct q_globals *gv)
 | 
			
		|||
  if (gv->m_factory->m_connless)
 | 
			
		||||
  {
 | 
			
		||||
    if (!(gv->config.many_sockets_mode == MSM_NO_UNICAST && gv->config.allowMulticast))
 | 
			
		||||
      GVTRACE ("Unicast Ports: discovery %"PRIu32" data %"PRIu32"\n", ddsi_conn_port (gv->disc_conn_uc), ddsi_conn_port (gv->data_conn_uc));
 | 
			
		||||
      GVLOG (DDS_LC_CONFIG, "Unicast Ports: discovery %"PRIu32" data %"PRIu32"\n", ddsi_conn_port (gv->disc_conn_uc), ddsi_conn_port (gv->data_conn_uc));
 | 
			
		||||
 | 
			
		||||
    if (gv->config.allowMulticast)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -1161,7 +1189,7 @@ int rtps_init (struct q_globals *gv)
 | 
			
		|||
  /* Create shared transmit connection */
 | 
			
		||||
 | 
			
		||||
  gv->tev_conn = gv->data_conn_uc;
 | 
			
		||||
  GVTRACE ("Timed event transmit port: %d\n", (int) ddsi_conn_port (gv->tev_conn));
 | 
			
		||||
  GVLOG (DDS_LC_CONFIG, "Timed event transmit port: %d\n", (int) ddsi_conn_port (gv->tev_conn));
 | 
			
		||||
 | 
			
		||||
#ifdef DDSI_INCLUDE_NETWORK_CHANNELS
 | 
			
		||||
  {
 | 
			
		||||
| 
						 | 
				
			
			@ -1189,7 +1217,7 @@ int rtps_init (struct q_globals *gv)
 | 
			
		|||
      {
 | 
			
		||||
        chptr->transmit_conn = gv->data_conn_uc;
 | 
			
		||||
      }
 | 
			
		||||
      GVTRACE ("channel %s: transmit port %d\n", chptr->name, (int) ddsi_tran_port (chptr->transmit_conn));
 | 
			
		||||
      GVLOG (DDS_LC_CONFIG, "channel %s: transmit port %d\n", chptr->name, (int) ddsi_tran_port (chptr->transmit_conn));
 | 
			
		||||
 | 
			
		||||
#ifdef DDSI_INCLUDE_BANDWIDTH_LIMITING
 | 
			
		||||
      if (chptr->auxiliary_bandwidth_limit > 0 || lookup_thread_properties (tname))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -188,7 +188,7 @@ int64_t check_and_handle_lease_expiration (struct q_globals *gv, nn_etime_t tnow
 | 
			
		|||
  ddsrt_mutex_lock (&gv->leaseheap_lock);
 | 
			
		||||
  while ((l = ddsrt_fibheap_min (&lease_fhdef, &gv->leaseheap)) != NULL && l->tsched.v <= tnowE.v)
 | 
			
		||||
  {
 | 
			
		||||
    nn_guid_t g = l->entity->guid;
 | 
			
		||||
    ddsi_guid_t g = l->entity->guid;
 | 
			
		||||
    enum entity_kind k = l->entity->kind;
 | 
			
		||||
 | 
			
		||||
    assert (l->tsched.v != TSCHED_NOT_ON_HEAP);
 | 
			
		||||
| 
						 | 
				
			
			@ -303,7 +303,7 @@ void handle_PMD (const struct receiver_state *rst, nn_wctime_t timestamp, uint32
 | 
			
		|||
  const struct CDRHeader *data = vdata; /* built-ins not deserialized (yet) */
 | 
			
		||||
  const int bswap = (data->identifier == CDR_LE) ^ (DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN);
 | 
			
		||||
  struct proxy_participant *pp;
 | 
			
		||||
  nn_guid_t ppguid;
 | 
			
		||||
  ddsi_guid_t ppguid;
 | 
			
		||||
  RSTTRACE (" PMD ST%x", statusinfo);
 | 
			
		||||
  if (data->identifier != CDR_LE && data->identifier != CDR_BE)
 | 
			
		||||
  {
 | 
			
		||||
| 
						 | 
				
			
			@ -318,7 +318,7 @@ void handle_PMD (const struct receiver_state *rst, nn_wctime_t timestamp, uint32
 | 
			
		|||
      else
 | 
			
		||||
      {
 | 
			
		||||
        const ParticipantMessageData_t *pmd = (ParticipantMessageData_t *) (data + 1);
 | 
			
		||||
        nn_guid_prefix_t p = nn_ntoh_guid_prefix (pmd->participantGuidPrefix);
 | 
			
		||||
        ddsi_guid_prefix_t p = nn_ntoh_guid_prefix (pmd->participantGuidPrefix);
 | 
			
		||||
        uint32_t kind = ntohl (pmd->kind);
 | 
			
		||||
        uint32_t length = bswap ? bswap4u (pmd->length) : pmd->length;
 | 
			
		||||
        RSTTRACE (" pp %"PRIx32":%"PRIx32":%"PRIx32" kind %u data %u", p.u[0], p.u[1], p.u[2], kind, length);
 | 
			
		||||
| 
						 | 
				
			
			@ -346,11 +346,11 @@ void handle_PMD (const struct receiver_state *rst, nn_wctime_t timestamp, uint32
 | 
			
		|||
    case NN_STATUSINFO_DISPOSE | NN_STATUSINFO_UNREGISTER:
 | 
			
		||||
      /* Serialized key; BE or LE doesn't matter as both fields are
 | 
			
		||||
         defined as octets.  */
 | 
			
		||||
      if (len < sizeof (struct CDRHeader) + sizeof (nn_guid_prefix_t))
 | 
			
		||||
      if (len < sizeof (struct CDRHeader) + sizeof (ddsi_guid_prefix_t))
 | 
			
		||||
        debug_print_rawdata (rst->gv, " SHORT3", data, len);
 | 
			
		||||
      else
 | 
			
		||||
      {
 | 
			
		||||
        ppguid.prefix = nn_ntoh_guid_prefix (*((nn_guid_prefix_t *) (data + 1)));
 | 
			
		||||
        ppguid.prefix = nn_ntoh_guid_prefix (*((ddsi_guid_prefix_t *) (data + 1)));
 | 
			
		||||
        ppguid.entityid.u = NN_ENTITYID_PARTICIPANT;
 | 
			
		||||
        if (delete_proxy_participant_by_guid (rst->gv, &ppguid, timestamp, 0) < 0)
 | 
			
		||||
          RSTTRACE (" unknown");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -38,6 +38,8 @@
 | 
			
		|||
#include "dds/ddsrt/avl.h"
 | 
			
		||||
#include "dds/ddsi/q_misc.h" /* for vendor_is_... */
 | 
			
		||||
 | 
			
		||||
#include "dds/ddsi/ddsi_plist_generic.h"
 | 
			
		||||
 | 
			
		||||
/* I am tempted to change LENGTH_UNLIMITED to 0 in the API (with -1
 | 
			
		||||
   supported for backwards compatibility) ... on the wire however
 | 
			
		||||
   it must be -1 */
 | 
			
		||||
| 
						 | 
				
			
			@ -88,25 +90,6 @@ struct flagset {
 | 
			
		|||
  uint64_t wanted;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Instructions for the generic serializer (&c) that handles most parameters.
 | 
			
		||||
   The "packed" attribute means single-byte instructions on GCC and Clang. */
 | 
			
		||||
enum pserop {
 | 
			
		||||
  XSTOP,
 | 
			
		||||
  XO, /* octet sequence */
 | 
			
		||||
  XS, /* string */
 | 
			
		||||
  XZ, /* string sequence */
 | 
			
		||||
  XE1, XE2, XE3, /* enum 0..1, 0..2, 0..3 */
 | 
			
		||||
  Xl, /* length, int32_t, -1 or >= 1 */
 | 
			
		||||
  Xi, Xix2, Xix3, Xix4, /* int32_t, 1 .. 4 in a row */
 | 
			
		||||
  Xu, Xux2, Xux3, Xux4, Xux5, /* uint32_t, 1 .. 5 in a row */
 | 
			
		||||
  XD, XDx2, /* duration, 1 .. 2 in a row */
 | 
			
		||||
  Xo, Xox2, /* octet, 1 .. 2 in a row */
 | 
			
		||||
  Xb, Xbx2, /* boolean, 1 .. 2 in a row */
 | 
			
		||||
  XbCOND, /* boolean: compare to ignore remainder if false (for use_... flags) */
 | 
			
		||||
  XG, /* GUID */
 | 
			
		||||
  XK /* keyhash */
 | 
			
		||||
} ddsrt_attribute_packed;
 | 
			
		||||
 | 
			
		||||
struct piddesc {
 | 
			
		||||
  nn_parameterid_t pid;  /* parameter id or PID_PAD if strictly local */
 | 
			
		||||
  uint16_t flags;        /* see PDF_xxx flags */
 | 
			
		||||
| 
						 | 
				
			
			@ -115,10 +98,10 @@ struct piddesc {
 | 
			
		|||
  size_t plist_offset;   /* offset from start of nn_plist_t */
 | 
			
		||||
  size_t size;           /* in-memory size for copying */
 | 
			
		||||
  union {
 | 
			
		||||
    /* descriptor for generic code: 4 is enough for the current set of
 | 
			
		||||
    /* descriptor for generic code: 12 is enough for the current set of
 | 
			
		||||
       parameters, compiler will warn if one ever tries to use more than
 | 
			
		||||
       will fit; on non-GCC/Clang and 32-bits machines */
 | 
			
		||||
    const enum pserop desc[4];
 | 
			
		||||
       will fit */
 | 
			
		||||
    const enum pserop desc[12];
 | 
			
		||||
    struct {
 | 
			
		||||
      dds_return_t (*deser) (void * __restrict dst, size_t * __restrict dstoff, struct flagset *flagset, uint64_t flag, const struct dd * __restrict dd, size_t * __restrict srcoff);
 | 
			
		||||
      dds_return_t (*ser) (struct nn_xmsg *xmsg, nn_parameterid_t pid, const void *src, size_t srcoff);
 | 
			
		||||
| 
						 | 
				
			
			@ -131,6 +114,8 @@ struct piddesc {
 | 
			
		|||
  dds_return_t (*deser_validate_xform) (void * __restrict dst, const struct dd * __restrict dd);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
extern inline bool pserop_seralign_is_1 (enum pserop op);
 | 
			
		||||
 | 
			
		||||
static void log_octetseq (uint32_t cat, const struct ddsrt_log_cfg *logcfg, uint32_t n, const unsigned char *xs);
 | 
			
		||||
static dds_return_t validate_history_qospolicy (const dds_history_qospolicy_t *q);
 | 
			
		||||
static dds_return_t validate_resource_limits_qospolicy (const dds_resource_limits_qospolicy_t *q);
 | 
			
		||||
| 
						 | 
				
			
			@ -325,7 +310,47 @@ static dds_return_t fini_locator (void * __restrict dst, size_t * __restrict dst
 | 
			
		|||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void fini_generic_partial (void * __restrict dst, size_t * __restrict dstoff, const enum pserop *desc, const enum pserop * const desc_end, bool aliased)
 | 
			
		||||
static size_t ser_generic_srcsize (const enum pserop * __restrict desc)
 | 
			
		||||
{
 | 
			
		||||
  size_t srcoff = 0, srcalign = 0;
 | 
			
		||||
#define SIMPLE(basecase_, type_) do {                          \
 | 
			
		||||
    const uint32_t cnt = 1 + (uint32_t) (*desc - (basecase_)); \
 | 
			
		||||
    const size_t align = alignof (type_);                      \
 | 
			
		||||
    srcalign = (align > srcalign) ? align : srcalign;          \
 | 
			
		||||
    srcoff = (srcoff + align - 1) & ~(align - 1);              \
 | 
			
		||||
    srcoff += cnt * sizeof (type_);                            \
 | 
			
		||||
  } while (0)
 | 
			
		||||
  while (true)
 | 
			
		||||
  {
 | 
			
		||||
    switch (*desc)
 | 
			
		||||
    {
 | 
			
		||||
      case XSTOP: return (srcoff + srcalign - 1) & ~(srcalign - 1);
 | 
			
		||||
      case XO: SIMPLE (XO, ddsi_octetseq_t); break;
 | 
			
		||||
      case XS: SIMPLE (XS, const char *); break;
 | 
			
		||||
      case XE1: case XE2: case XE3: SIMPLE (*desc, unsigned); break;
 | 
			
		||||
      case Xi: case Xix2: case Xix3: case Xix4: SIMPLE (Xi, int32_t); break;
 | 
			
		||||
      case Xu: case Xux2: case Xux3: case Xux4: case Xux5: SIMPLE (Xu, uint32_t); break;
 | 
			
		||||
      case XD: case XDx2: SIMPLE (XD, dds_duration_t); break;
 | 
			
		||||
      case Xo: case Xox2: SIMPLE (Xo, unsigned char); break;
 | 
			
		||||
      case Xb: case Xbx2: SIMPLE (Xb, unsigned char); break;
 | 
			
		||||
      case XbCOND: SIMPLE (XbCOND, unsigned char); break;
 | 
			
		||||
      case XG: SIMPLE (XG, ddsi_guid_t); break;
 | 
			
		||||
      case XK: SIMPLE (XK, nn_keyhash_t); break;
 | 
			
		||||
      case XbPROP: SIMPLE (XbPROP, unsigned char); break;
 | 
			
		||||
      case XQ: SIMPLE (XQ, ddsi_octetseq_t); while (*++desc != XSTOP) { } break;
 | 
			
		||||
      case Xopt: break;
 | 
			
		||||
    }
 | 
			
		||||
    desc++;
 | 
			
		||||
  }
 | 
			
		||||
#undef SIMPLE
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t plist_memsize_generic (const enum pserop * __restrict desc)
 | 
			
		||||
{
 | 
			
		||||
  return ser_generic_srcsize (desc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void fini_generic_embeddable (void * __restrict dst, size_t * __restrict dstoff, const enum pserop *desc, const enum pserop * const desc_end, bool aliased)
 | 
			
		||||
{
 | 
			
		||||
#define COMPLEX(basecase_, type_, cleanup_unaliased_, cleanup_always_) do { \
 | 
			
		||||
    type_ *x = deser_generic_dst (dst, dstoff, alignof (type_));            \
 | 
			
		||||
| 
						 | 
				
			
			@ -344,17 +369,29 @@ static void fini_generic_partial (void * __restrict dst, size_t * __restrict dst
 | 
			
		|||
      case XSTOP: return;
 | 
			
		||||
      case XO: COMPLEX (XO, ddsi_octetseq_t, ddsrt_free (x->value), (void) 0); break;
 | 
			
		||||
      case XS: COMPLEX (XS, char *, ddsrt_free (*x), (void) 0); break;
 | 
			
		||||
      case XZ: COMPLEX (XZ, ddsi_stringseq_t, { for (uint32_t i = 0; i < x->n; i++) ddsrt_free (x->strs[i]); }, ddsrt_free (x->strs)); break;
 | 
			
		||||
      case XE1: case XE2: case XE3: COMPLEX (*desc, unsigned, (void) 0, (void) 0); break;
 | 
			
		||||
      case Xi: case Xix2: case Xix3: case Xix4: SIMPLE (Xi, int32_t); break;
 | 
			
		||||
      case Xu: case Xux2: case Xux3: case Xux4: case Xux5: SIMPLE (Xu, uint32_t); break;
 | 
			
		||||
      case Xl: SIMPLE (Xl, int32_t); break;
 | 
			
		||||
      case XD: case XDx2: SIMPLE (XD, dds_duration_t); break;
 | 
			
		||||
      case Xo: case Xox2: SIMPLE (Xo, unsigned char); break;
 | 
			
		||||
      case Xb: case Xbx2: SIMPLE (Xb, unsigned char); break;
 | 
			
		||||
      case XbCOND: SIMPLE (XbCOND, unsigned char); break;
 | 
			
		||||
      case XG: SIMPLE (XG, nn_guid_t); break;
 | 
			
		||||
      case XG: SIMPLE (XG, ddsi_guid_t); break;
 | 
			
		||||
      case XK: SIMPLE (XK, nn_keyhash_t); break;
 | 
			
		||||
      case XbPROP: SIMPLE (XbPROP, unsigned char); break;
 | 
			
		||||
      case XQ:
 | 
			
		||||
        /* non-nested, so never a need to deallocate only some of the entries and no complications
 | 
			
		||||
           in locating the end of the sequence element description */
 | 
			
		||||
        COMPLEX (XQ, ddsi_octetseq_t, {
 | 
			
		||||
          const size_t elem_size = ser_generic_srcsize (desc + 1);
 | 
			
		||||
          for (uint32_t i = 0; i < x->length; i++) {
 | 
			
		||||
            size_t elem_off = i * elem_size;
 | 
			
		||||
            fini_generic_embeddable (x->value, &elem_off, desc + 1, desc_end, aliased);
 | 
			
		||||
          }
 | 
			
		||||
        }, ddsrt_free (x->value));
 | 
			
		||||
        while (desc + 1 != desc_end && *++desc != XSTOP) { }
 | 
			
		||||
        break;
 | 
			
		||||
      case Xopt: break;
 | 
			
		||||
    }
 | 
			
		||||
    desc++;
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -362,6 +399,26 @@ static void fini_generic_partial (void * __restrict dst, size_t * __restrict dst
 | 
			
		|||
#undef COMPLEX
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static size_t pserop_memalign (enum pserop op)
 | 
			
		||||
{
 | 
			
		||||
  switch (op)
 | 
			
		||||
  {
 | 
			
		||||
    case XO: case XQ: return alignof (ddsi_octetseq_t);
 | 
			
		||||
    case XS: return alignof (char *);
 | 
			
		||||
    case XG: return alignof (ddsi_guid_t);
 | 
			
		||||
    case XK: return alignof (nn_keyhash_t);
 | 
			
		||||
    case Xb: case Xbx2: return 1;
 | 
			
		||||
    case Xo: case Xox2: return 1;
 | 
			
		||||
    case XbCOND: case XbPROP: return 1;
 | 
			
		||||
    case XE1: case XE2: case XE3: return sizeof (uint32_t);
 | 
			
		||||
    case Xi: case Xix2: case Xix3: case Xix4: return sizeof (int32_t);
 | 
			
		||||
    case Xu: case Xux2: case Xux3: case Xux4: case Xux5: return sizeof (uint32_t);
 | 
			
		||||
    case XD: case XDx2: return alignof (dds_duration_t);
 | 
			
		||||
    case XSTOP: case Xopt: assert (0);
 | 
			
		||||
  }
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static dds_return_t deser_generic (void * __restrict dst, size_t * __restrict dstoff, struct flagset *flagset, uint64_t flag, const struct dd * __restrict dd, size_t * __restrict srcoff, const enum pserop * __restrict desc)
 | 
			
		||||
{
 | 
			
		||||
  enum pserop const * const desc_in = desc;
 | 
			
		||||
| 
						 | 
				
			
			@ -376,8 +433,7 @@ static dds_return_t deser_generic (void * __restrict dst, size_t * __restrict ds
 | 
			
		|||
    switch (*desc)
 | 
			
		||||
    {
 | 
			
		||||
      case XSTOP:
 | 
			
		||||
        *flagset->present |= flag;
 | 
			
		||||
        return 0;
 | 
			
		||||
        goto success;
 | 
			
		||||
      case XO: { /* octet sequence */
 | 
			
		||||
        ddsi_octetseq_t * const x = deser_generic_dst (dst, dstoff, alignof (ddsi_octetseq_t));
 | 
			
		||||
        if (deser_uint32 (&x->length, dd, srcoff) < 0 || dd->bufsz - *srcoff < x->length)
 | 
			
		||||
| 
						 | 
				
			
			@ -400,22 +456,6 @@ static dds_return_t deser_generic (void * __restrict dst, size_t * __restrict ds
 | 
			
		|||
        *dstoff += sizeof (*x);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case XZ: { /* string sequence: repeatedly read a string */
 | 
			
		||||
        ddsi_stringseq_t * const x = deser_generic_dst (dst, dstoff, alignof (ddsi_stringseq_t));
 | 
			
		||||
        /* sequence of string: length <data> length <data> ..., where each length is aligned
 | 
			
		||||
           to a multiple of 4 bytes and the lengths are all at least 1, therefore all but the
 | 
			
		||||
           last entry need 8 bytes and the final one at least 5; checking this protects us
 | 
			
		||||
           against allocating large amount of memory */
 | 
			
		||||
        if (deser_uint32 (&x->n, dd, srcoff) < 0 || x->n > (dd->bufsz - *srcoff + 7) / 8)
 | 
			
		||||
          goto fail;
 | 
			
		||||
        x->strs = x->n ? ddsrt_malloc (x->n * sizeof (*x->strs)) : NULL;
 | 
			
		||||
        size_t tmpoff = 0;
 | 
			
		||||
        for (uint32_t i = 0; i < x->n; i++)
 | 
			
		||||
          if (deser_generic (x->strs, &tmpoff, flagset, flag, dd, srcoff, (enum pserop []) { XS, XSTOP }) < 0)
 | 
			
		||||
            goto fail;
 | 
			
		||||
        *dstoff += sizeof (*x);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case XE1: case XE2: case XE3: { /* enum with max allowed value */
 | 
			
		||||
        unsigned * const x = deser_generic_dst (dst, dstoff, alignof (int));
 | 
			
		||||
        const uint32_t maxval = 1 + (uint32_t) (*desc - XE1);
 | 
			
		||||
| 
						 | 
				
			
			@ -444,15 +484,6 @@ static dds_return_t deser_generic (void * __restrict dst, size_t * __restrict ds
 | 
			
		|||
        *dstoff += cnt * sizeof (*x);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case Xl: { /* length(s): int32_t, -1 or >= 1 */
 | 
			
		||||
        int32_t * const x = deser_generic_dst (dst, dstoff, alignof (uint32_t));
 | 
			
		||||
        const uint32_t cnt = 1 + (uint32_t) (*desc - Xl);
 | 
			
		||||
        for (uint32_t i = 0; i < cnt; i++)
 | 
			
		||||
          if (deser_uint32 ((uint32_t *) &x[i], dd, srcoff) < 0 || (x[i] < 1 && x[i] != DDS_LENGTH_UNLIMITED))
 | 
			
		||||
            goto fail;
 | 
			
		||||
        *dstoff += cnt * sizeof (*x);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case XD: case XDx2: { /* duration(s): int64_t <=> int32_t.uint32_t (seconds.fraction) */
 | 
			
		||||
        dds_duration_t * const x = deser_generic_dst (dst, dstoff, alignof (dds_duration_t));
 | 
			
		||||
        const uint32_t cnt = 1 + (uint32_t) (*desc - XD);
 | 
			
		||||
| 
						 | 
				
			
			@ -491,8 +522,14 @@ static dds_return_t deser_generic (void * __restrict dst, size_t * __restrict ds
 | 
			
		|||
        *dstoff += cnt * sizeof (*x);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case XbPROP: { /* "propagate" flag, boolean, implied in serialized representation */
 | 
			
		||||
        unsigned char * const x = deser_generic_dst (dst, dstoff, alignof (unsigned char));
 | 
			
		||||
        *x = 1;
 | 
			
		||||
        *dstoff += sizeof (*x);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case XG: { /* GUID */
 | 
			
		||||
        nn_guid_t * const x = deser_generic_dst (dst, dstoff, alignof (nn_guid_t));
 | 
			
		||||
        ddsi_guid_t * const x = deser_generic_dst (dst, dstoff, alignof (ddsi_guid_t));
 | 
			
		||||
        if (dd->bufsz - *srcoff < sizeof (*x))
 | 
			
		||||
          goto fail;
 | 
			
		||||
        memcpy (x, dd->buf + *srcoff, sizeof (*x));
 | 
			
		||||
| 
						 | 
				
			
			@ -510,61 +547,139 @@ static dds_return_t deser_generic (void * __restrict dst, size_t * __restrict ds
 | 
			
		|||
        *dstoff += sizeof (*x);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case XQ: { /* non-nested but otherwise arbitrary sequence, so no nested mallocs */
 | 
			
		||||
        ddsi_octetseq_t * const x = deser_generic_dst (dst, dstoff, alignof (ddsi_octetseq_t));
 | 
			
		||||
        if (deser_uint32 (&x->length, dd, srcoff) < 0 || x->length > dd->bufsz - *srcoff)
 | 
			
		||||
          goto fail;
 | 
			
		||||
        const size_t elem_size = ser_generic_srcsize (desc + 1);
 | 
			
		||||
        x->value = x->length ? ddsrt_malloc (x->length * elem_size) : NULL;
 | 
			
		||||
        for (uint32_t i = 0; i < x->length; i++)
 | 
			
		||||
        {
 | 
			
		||||
          size_t elem_off = i * elem_size;
 | 
			
		||||
          if (deser_generic (x->value, &elem_off, flagset, flag, dd, srcoff, desc + 1) < 0)
 | 
			
		||||
          {
 | 
			
		||||
            ddsrt_free (x->value);
 | 
			
		||||
            goto fail;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        *dstoff += sizeof (*x);
 | 
			
		||||
        while (*++desc != XSTOP) { }
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case Xopt: { /* remainder is optional; alignment is very nearly always 4 */
 | 
			
		||||
        bool end_of_input;
 | 
			
		||||
        if (pserop_seralign_is_1 (desc[1]))
 | 
			
		||||
          end_of_input = (*srcoff + 1 > dd->bufsz);
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
          *srcoff = (*srcoff + 3) & ~(size_t)3;
 | 
			
		||||
          end_of_input = (*srcoff + 4 > dd->bufsz);
 | 
			
		||||
        }
 | 
			
		||||
        if (end_of_input)
 | 
			
		||||
        {
 | 
			
		||||
          void * const x = deser_generic_dst (dst, dstoff, pserop_memalign (desc[1]));
 | 
			
		||||
          size_t rem_size = ser_generic_srcsize (desc + 1);
 | 
			
		||||
          memset (x, 0, rem_size);
 | 
			
		||||
          goto success;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    desc++;
 | 
			
		||||
  }
 | 
			
		||||
success:
 | 
			
		||||
  *flagset->present |= flag;
 | 
			
		||||
  return 0;
 | 
			
		||||
 | 
			
		||||
fail:
 | 
			
		||||
  fini_generic_partial (dst, &dstoff_in, desc_in, desc, *flagset->aliased & flag);
 | 
			
		||||
  fini_generic_embeddable (dst, &dstoff_in, desc_in, desc, *flagset->aliased & flag);
 | 
			
		||||
  *flagset->present &= ~flag;
 | 
			
		||||
  *flagset->aliased &= ~flag;
 | 
			
		||||
  return DDS_RETCODE_BAD_PARAMETER;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static size_t ser_generic_size (const void *src, size_t srcoff, const enum pserop * __restrict desc)
 | 
			
		||||
dds_return_t plist_deser_generic (void * __restrict dst, const void * __restrict src, size_t srcsize, bool bswap, const enum pserop * __restrict desc)
 | 
			
		||||
{
 | 
			
		||||
  struct dd dd = {
 | 
			
		||||
    .buf = src,
 | 
			
		||||
    .bufsz = srcsize,
 | 
			
		||||
    .bswap = bswap,
 | 
			
		||||
    .protocol_version = {0,0},
 | 
			
		||||
    .vendorid = NN_VENDORID_ECLIPSE,
 | 
			
		||||
    .factory = NULL
 | 
			
		||||
  };
 | 
			
		||||
  uint64_t present = 0, aliased = 0;
 | 
			
		||||
  struct flagset fs = { .present = &present, .aliased = &aliased, .wanted = 1 };
 | 
			
		||||
  size_t dstoff = 0, srcoff = 0;
 | 
			
		||||
  return deser_generic (dst, &dstoff, &fs, 1, &dd, &srcoff, desc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ser_generic_size_embeddable (size_t *dstoff, const void *src, size_t srcoff, const enum pserop * __restrict desc)
 | 
			
		||||
{
 | 
			
		||||
  size_t dstoff = 0;
 | 
			
		||||
#define COMPLEX(basecase_, type_, dstoff_update_) do {                  \
 | 
			
		||||
    type_ const *x = deser_generic_src (src, &srcoff, alignof (type_)); \
 | 
			
		||||
    const uint32_t cnt = 1 + (uint32_t) (*desc - (basecase_));          \
 | 
			
		||||
    for (uint32_t xi = 0; xi < cnt; xi++, x++) { dstoff_update_; }      \
 | 
			
		||||
    srcoff += cnt * sizeof (*x);                                        \
 | 
			
		||||
  } while (0)
 | 
			
		||||
#define SIMPLE1(basecase_, type_) COMPLEX (basecase_, type_, dstoff = dstoff + sizeof (*x))
 | 
			
		||||
#define SIMPLE4(basecase_, type_) COMPLEX (basecase_, type_, dstoff = align4size (dstoff) + sizeof (*x))
 | 
			
		||||
#define SIMPLE1(basecase_, type_) COMPLEX (basecase_, type_, *dstoff = *dstoff + sizeof (*x))
 | 
			
		||||
#define SIMPLE4(basecase_, type_) COMPLEX (basecase_, type_, *dstoff = align4size (*dstoff) + sizeof (*x))
 | 
			
		||||
  while (true)
 | 
			
		||||
  {
 | 
			
		||||
    switch (*desc)
 | 
			
		||||
    {
 | 
			
		||||
      case XSTOP: return dstoff;
 | 
			
		||||
      case XO: COMPLEX (XO, ddsi_octetseq_t, dstoff = align4size (dstoff) + 4 + x->length); break;
 | 
			
		||||
      case XS: COMPLEX (XS, const char *, dstoff = align4size (dstoff) + 4 + strlen (*x) + 1); break;
 | 
			
		||||
      case XZ: COMPLEX (XZ, ddsi_stringseq_t, {
 | 
			
		||||
        dstoff = align4size (dstoff) + 4;
 | 
			
		||||
        for (uint32_t i = 0; i < x->n; i++)
 | 
			
		||||
          dstoff = align4size (dstoff) + 4 + strlen (x->strs[i]) + 1;
 | 
			
		||||
      }); break;
 | 
			
		||||
      case XE1: case XE2: case XE3: COMPLEX (*desc, unsigned, dstoff = align4size (dstoff) + 4); break;
 | 
			
		||||
      case XSTOP: return;
 | 
			
		||||
      case XO: COMPLEX (XO, ddsi_octetseq_t, *dstoff = align4size (*dstoff) + 4 + x->length); break;
 | 
			
		||||
      case XS: COMPLEX (XS, const char *, *dstoff = align4size (*dstoff) + 4 + strlen (*x) + 1); break;
 | 
			
		||||
      case XE1: case XE2: case XE3: COMPLEX (*desc, unsigned, *dstoff = align4size (*dstoff) + 4); break;
 | 
			
		||||
      case Xi: case Xix2: case Xix3: case Xix4: SIMPLE4 (Xi, int32_t); break;
 | 
			
		||||
      case Xu: case Xux2: case Xux3: case Xux4: case Xux5: SIMPLE4 (Xu, uint32_t); break;
 | 
			
		||||
      case Xl: SIMPLE4 (Xl, int32_t); break;
 | 
			
		||||
      case XD: case XDx2: SIMPLE4 (XD, dds_duration_t); break;
 | 
			
		||||
      case Xo: case Xox2: SIMPLE1 (Xo, unsigned char); break;
 | 
			
		||||
      case Xb: case Xbx2: SIMPLE1 (Xb, unsigned char); break;
 | 
			
		||||
      case XbCOND: SIMPLE1 (XbCOND, unsigned char); break;
 | 
			
		||||
      case XG: SIMPLE1 (XG, nn_guid_t); break;
 | 
			
		||||
      case XG: SIMPLE1 (XG, ddsi_guid_t); break;
 | 
			
		||||
      case XK: SIMPLE1 (XK, nn_keyhash_t); break;
 | 
			
		||||
      case XbPROP: /* "propagate" boolean: when 'false'; no serialisation; no size; force early out */
 | 
			
		||||
               COMPLEX (XbPROP, unsigned char, if (! *x) return); break;
 | 
			
		||||
      case XQ: COMPLEX (XQ, ddsi_octetseq_t, {
 | 
			
		||||
        const size_t elem_size = ser_generic_srcsize (desc + 1);
 | 
			
		||||
        *dstoff = align4size (*dstoff) + 4;
 | 
			
		||||
        for (uint32_t i = 0; i < x->length; i++)
 | 
			
		||||
          ser_generic_size_embeddable (dstoff, x->value, i * elem_size, desc + 1);
 | 
			
		||||
      }); while (*++desc != XSTOP) { } break;
 | 
			
		||||
      case Xopt: break;
 | 
			
		||||
    }
 | 
			
		||||
    desc++;
 | 
			
		||||
  }
 | 
			
		||||
#undef SIMPLE
 | 
			
		||||
#undef SIMPLE4
 | 
			
		||||
#undef SIMPLE1
 | 
			
		||||
#undef COMPLEX
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static dds_return_t ser_generic (struct nn_xmsg *xmsg, nn_parameterid_t pid, const void *src, size_t srcoff, const enum pserop * __restrict desc)
 | 
			
		||||
static size_t ser_generic_size (const void *src, size_t srcoff, const enum pserop * __restrict desc)
 | 
			
		||||
{
 | 
			
		||||
  char * const data = nn_xmsg_addpar (xmsg, pid, ser_generic_size (src, srcoff, desc));
 | 
			
		||||
  size_t dstoff = 0;
 | 
			
		||||
  ser_generic_size_embeddable (&dstoff, src, srcoff, desc);
 | 
			
		||||
  return dstoff;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static uint32_t ser_generic_count (const ddsi_octetseq_t *src, size_t elem_size, const enum pserop * __restrict desc)
 | 
			
		||||
{
 | 
			
		||||
  /* This whole thing exists solely for dealing with the vile "propagate" boolean, which must come first in an
 | 
			
		||||
     element, or one can't deserialize it at all.  Therefore, if desc doesn't start with XbPROP, all "length"
 | 
			
		||||
     elements are included in the output */
 | 
			
		||||
  if (*desc != XbPROP)
 | 
			
		||||
    return src->length;
 | 
			
		||||
  /* and if it does start with XbPROP, only those for which it is true are included */
 | 
			
		||||
  uint32_t count = 0;
 | 
			
		||||
  for (uint32_t i = 0; i < src->length; i++)
 | 
			
		||||
    if (src->value[i * elem_size])
 | 
			
		||||
      count++;
 | 
			
		||||
  return count;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static dds_return_t ser_generic_embeddable (char * const data, size_t *dstoff, const void *src, size_t srcoff, const enum pserop * __restrict desc)
 | 
			
		||||
{
 | 
			
		||||
  while (true)
 | 
			
		||||
  {
 | 
			
		||||
    switch (*desc)
 | 
			
		||||
| 
						 | 
				
			
			@ -573,134 +688,151 @@ static dds_return_t ser_generic (struct nn_xmsg *xmsg, nn_parameterid_t pid, con
 | 
			
		|||
        return 0;
 | 
			
		||||
      case XO: { /* octet sequence */
 | 
			
		||||
        ddsi_octetseq_t const * const x = deser_generic_src (src, &srcoff, alignof (ddsi_octetseq_t));
 | 
			
		||||
        char * const p = ser_generic_align4 (data, &dstoff);
 | 
			
		||||
        char * const p = ser_generic_align4 (data, dstoff);
 | 
			
		||||
        *((uint32_t *) p) = x->length;
 | 
			
		||||
        if (x->length) memcpy (p + 4, x->value, x->length);
 | 
			
		||||
        dstoff += 4 + x->length;
 | 
			
		||||
        *dstoff += 4 + x->length;
 | 
			
		||||
        srcoff += sizeof (*x);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case XS: { /* string */
 | 
			
		||||
        char const * const * const x = deser_generic_src (src, &srcoff, alignof (char *));
 | 
			
		||||
        const uint32_t size = (uint32_t) (strlen (*x) + 1);
 | 
			
		||||
        char * const p = ser_generic_align4 (data, &dstoff);
 | 
			
		||||
        char * const p = ser_generic_align4 (data, dstoff);
 | 
			
		||||
        *((uint32_t *) p) = size;
 | 
			
		||||
        memcpy (p + 4, *x, size);
 | 
			
		||||
        dstoff += 4 + size;
 | 
			
		||||
        srcoff += sizeof (*x);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case XZ: { /* string sequence */
 | 
			
		||||
        ddsi_stringseq_t const * const x = deser_generic_src (src, &srcoff, alignof (ddsi_stringseq_t));
 | 
			
		||||
        char * const p = ser_generic_align4 (data, &dstoff);
 | 
			
		||||
        *((uint32_t *) p) = x->n;
 | 
			
		||||
        dstoff += 4;
 | 
			
		||||
        for (uint32_t i = 0; i < x->n; i++)
 | 
			
		||||
        {
 | 
			
		||||
          char * const q = ser_generic_align4 (data, &dstoff);
 | 
			
		||||
          const uint32_t size = (uint32_t) (strlen (x->strs[i]) + 1);
 | 
			
		||||
          *((uint32_t *) q) = size;
 | 
			
		||||
          memcpy (q + 4, x->strs[i], size);
 | 
			
		||||
          dstoff += 4 + size;
 | 
			
		||||
        }
 | 
			
		||||
        *dstoff += 4 + size;
 | 
			
		||||
        srcoff += sizeof (*x);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case XE1: case XE2: case XE3: { /* enum */
 | 
			
		||||
        unsigned const * const x = deser_generic_src (src, &srcoff, alignof (unsigned));
 | 
			
		||||
        uint32_t * const p = ser_generic_align4 (data, &dstoff);
 | 
			
		||||
        uint32_t * const p = ser_generic_align4 (data, dstoff);
 | 
			
		||||
        *p = (uint32_t) *x;
 | 
			
		||||
        dstoff += 4;
 | 
			
		||||
        *dstoff += 4;
 | 
			
		||||
        srcoff += sizeof (*x);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case Xi: case Xix2: case Xix3: case Xix4: { /* int32_t(s) */
 | 
			
		||||
        int32_t const * const x = deser_generic_src (src, &srcoff, alignof (int32_t));
 | 
			
		||||
        const uint32_t cnt = 1 + (uint32_t) (*desc - Xi);
 | 
			
		||||
        int32_t * const p = ser_generic_align4 (data, &dstoff);
 | 
			
		||||
        int32_t * const p = ser_generic_align4 (data, dstoff);
 | 
			
		||||
        for (uint32_t i = 0; i < cnt; i++)
 | 
			
		||||
          p[i] = x[i];
 | 
			
		||||
        dstoff += cnt * sizeof (*x);
 | 
			
		||||
        *dstoff += cnt * sizeof (*x);
 | 
			
		||||
        srcoff += cnt * sizeof (*x);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      case Xu: case Xux2: case Xux3: case Xux4: case Xux5:  { /* uint32_t(s) */
 | 
			
		||||
        uint32_t const * const x = deser_generic_src (src, &srcoff, alignof (uint32_t));
 | 
			
		||||
        const uint32_t cnt = 1 + (uint32_t) (*desc - Xu);
 | 
			
		||||
        uint32_t * const p = ser_generic_align4 (data, &dstoff);
 | 
			
		||||
        uint32_t * const p = ser_generic_align4 (data, dstoff);
 | 
			
		||||
        for (uint32_t i = 0; i < cnt; i++)
 | 
			
		||||
          p[i] = x[i];
 | 
			
		||||
        dstoff += cnt * sizeof (*x);
 | 
			
		||||
        srcoff += cnt * sizeof (*x);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      case Xl: { /* int32_t(s) */
 | 
			
		||||
        int32_t const * const x = deser_generic_src (src, &srcoff, alignof (uint32_t));
 | 
			
		||||
        const uint32_t cnt = 1 + (uint32_t) (*desc - Xu);
 | 
			
		||||
        int32_t * const p = ser_generic_align4 (data, &dstoff);
 | 
			
		||||
        for (uint32_t i = 0; i < cnt; i++)
 | 
			
		||||
          p[i] = x[i];
 | 
			
		||||
        dstoff += cnt * sizeof (*x);
 | 
			
		||||
        *dstoff += cnt * sizeof (*x);
 | 
			
		||||
        srcoff += cnt * sizeof (*x);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case XD: case XDx2: { /* duration(s): int64_t <=> int32_t.uint32_t (seconds.fraction) */
 | 
			
		||||
        dds_duration_t const * const x = deser_generic_src (src, &srcoff, alignof (dds_duration_t));
 | 
			
		||||
        const uint32_t cnt = 1 + (uint32_t) (*desc - XD);
 | 
			
		||||
        uint32_t * const p = ser_generic_align4 (data, &dstoff);
 | 
			
		||||
        uint32_t * const p = ser_generic_align4 (data, dstoff);
 | 
			
		||||
        for (uint32_t i = 0; i < cnt; i++)
 | 
			
		||||
        {
 | 
			
		||||
          ddsi_duration_t tmp = nn_to_ddsi_duration (x[i]);
 | 
			
		||||
          p[2 * i + 0] = (uint32_t) tmp.seconds;
 | 
			
		||||
          p[2 * i + 1] = tmp.fraction;
 | 
			
		||||
        }
 | 
			
		||||
        dstoff += 2 * cnt * sizeof (uint32_t);
 | 
			
		||||
        *dstoff += 2 * cnt * sizeof (uint32_t);
 | 
			
		||||
        srcoff += cnt * sizeof (*x);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case Xo: case Xox2: { /* octet(s) */
 | 
			
		||||
        unsigned char const * const x = deser_generic_src (src, &srcoff, alignof (unsigned char));
 | 
			
		||||
        const uint32_t cnt = 1 + (uint32_t) (*desc - Xo);
 | 
			
		||||
        char * const p = data + dstoff;
 | 
			
		||||
        char * const p = data + *dstoff;
 | 
			
		||||
        memcpy (p, x, cnt);
 | 
			
		||||
        dstoff += cnt;
 | 
			
		||||
        *dstoff += cnt;
 | 
			
		||||
        srcoff += cnt * sizeof (*x);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case Xb: case Xbx2: case XbCOND: { /* boolean(s) */
 | 
			
		||||
        unsigned char const * const x = deser_generic_src (src, &srcoff, alignof (unsigned char));
 | 
			
		||||
        const uint32_t cnt = (*desc == Xbx2) ? 2 : 1; /* <<<< beware! */
 | 
			
		||||
        char * const p = data + dstoff;
 | 
			
		||||
        char * const p = data + *dstoff;
 | 
			
		||||
        memcpy (p, x, cnt);
 | 
			
		||||
        dstoff += cnt;
 | 
			
		||||
        *dstoff += cnt;
 | 
			
		||||
        srcoff += cnt * sizeof (*x);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case XbPROP: { /* "propagate" boolean: don't serialize, skip it and everything that follows if false */
 | 
			
		||||
        unsigned char const * const x = deser_generic_src (src, &srcoff, alignof (unsigned char));
 | 
			
		||||
        if (! *x) return 0;
 | 
			
		||||
        srcoff++;
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case XG: { /* GUID */
 | 
			
		||||
        nn_guid_t const * const x = deser_generic_src (src, &srcoff, alignof (nn_guid_t));
 | 
			
		||||
        const nn_guid_t xn = nn_hton_guid (*x);
 | 
			
		||||
        char * const p = data + dstoff;
 | 
			
		||||
        ddsi_guid_t const * const x = deser_generic_src (src, &srcoff, alignof (ddsi_guid_t));
 | 
			
		||||
        const ddsi_guid_t xn = nn_hton_guid (*x);
 | 
			
		||||
        char * const p = data + *dstoff;
 | 
			
		||||
        memcpy (p, &xn, sizeof (xn));
 | 
			
		||||
        dstoff += sizeof (xn);
 | 
			
		||||
        *dstoff += sizeof (xn);
 | 
			
		||||
        srcoff += sizeof (*x);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case XK: { /* keyhash */
 | 
			
		||||
        nn_keyhash_t const * const x = deser_generic_src (src, &srcoff, alignof (nn_keyhash_t));
 | 
			
		||||
        char * const p = data + dstoff;
 | 
			
		||||
        char * const p = data + *dstoff;
 | 
			
		||||
        memcpy (p, x, sizeof (*x));
 | 
			
		||||
        dstoff += sizeof (*x);
 | 
			
		||||
        *dstoff += sizeof (*x);
 | 
			
		||||
        srcoff += sizeof (*x);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case XQ: {
 | 
			
		||||
        ddsi_octetseq_t const * const x = deser_generic_src (src, &srcoff, alignof (ddsi_octetseq_t));
 | 
			
		||||
        char * const p = ser_generic_align4 (data, dstoff);
 | 
			
		||||
        *dstoff += 4;
 | 
			
		||||
        if (x->length == 0)
 | 
			
		||||
          *((uint32_t *) p) = 0;
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
          const size_t elem_size = ser_generic_srcsize (desc + 1);
 | 
			
		||||
          *((uint32_t *) p) = ser_generic_count (x, elem_size, desc + 1);
 | 
			
		||||
          for (uint32_t i = 0; i < x->length; i++)
 | 
			
		||||
            ser_generic_embeddable (data, dstoff, x->value, i * elem_size, desc + 1);
 | 
			
		||||
        }
 | 
			
		||||
        srcoff += sizeof (*x);
 | 
			
		||||
        while (*++desc != XSTOP) { }
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case Xopt:
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
    desc++;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static dds_return_t unalias_generic (void * __restrict dst, size_t * __restrict dstoff, const enum pserop * __restrict desc)
 | 
			
		||||
static dds_return_t ser_generic (struct nn_xmsg *xmsg, nn_parameterid_t pid, const void *src, size_t srcoff, const enum pserop * __restrict desc)
 | 
			
		||||
{
 | 
			
		||||
  char * const data = nn_xmsg_addpar (xmsg, pid, ser_generic_size (src, srcoff, desc));
 | 
			
		||||
  size_t dstoff = 0;
 | 
			
		||||
  return ser_generic_embeddable (data, &dstoff, src, srcoff, desc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dds_return_t plist_ser_generic (void **dst, size_t *dstsize, const void *src, const enum pserop * __restrict desc)
 | 
			
		||||
{
 | 
			
		||||
  const size_t srcoff = 0;
 | 
			
		||||
  size_t dstoff = 0;
 | 
			
		||||
  dds_return_t ret;
 | 
			
		||||
  *dstsize = ser_generic_size (src, srcoff, desc);
 | 
			
		||||
  if ((*dst = ddsrt_malloc (*dstsize == 0 ? 1 : *dstsize)) == NULL)
 | 
			
		||||
    return DDS_RETCODE_OUT_OF_RESOURCES;
 | 
			
		||||
  ret = ser_generic_embeddable (*dst, &dstoff, src, srcoff, desc);
 | 
			
		||||
  assert (dstoff == *dstsize);
 | 
			
		||||
  return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static dds_return_t unalias_generic (void * __restrict dst, size_t * __restrict dstoff, bool gen_seq_aliased, const enum pserop * __restrict desc)
 | 
			
		||||
{
 | 
			
		||||
#define COMPLEX(basecase_, type_, ...) do {                      \
 | 
			
		||||
    type_ *x = deser_generic_dst (dst, dstoff, alignof (type_)); \
 | 
			
		||||
| 
						 | 
				
			
			@ -717,21 +849,36 @@ static dds_return_t unalias_generic (void * __restrict dst, size_t * __restrict
 | 
			
		|||
        return 0;
 | 
			
		||||
      case XO: COMPLEX (XO, ddsi_octetseq_t, if (x->value) { x->value = ddsrt_memdup (x->value, x->length); }); break;
 | 
			
		||||
      case XS: COMPLEX (XS, char *, if (*x) { *x = ddsrt_strdup (*x); }); break;
 | 
			
		||||
      case XZ: COMPLEX (XZ, ddsi_stringseq_t, if (x->n) {
 | 
			
		||||
        x->strs = ddsrt_memdup (x->strs, x->n * sizeof (*x->strs));
 | 
			
		||||
        for (uint32_t i = 0; i < x->n; i++)
 | 
			
		||||
          x->strs[i] = ddsrt_strdup (x->strs[i]);
 | 
			
		||||
      }); break;
 | 
			
		||||
      case XE1: case XE2: case XE3: COMPLEX (*desc, unsigned, (void) 0); break;
 | 
			
		||||
      case Xi: case Xix2: case Xix3: case Xix4: SIMPLE (Xi, int32_t); break;
 | 
			
		||||
      case Xu: case Xux2: case Xux3: case Xux4: case Xux5: SIMPLE (Xu, uint32_t); break;
 | 
			
		||||
      case Xl: SIMPLE (Xl, int32_t); break;
 | 
			
		||||
      case XD: case XDx2: SIMPLE (XD, dds_duration_t); break;
 | 
			
		||||
      case Xo: case Xox2: SIMPLE (Xo, unsigned char); break;
 | 
			
		||||
      case Xb: case Xbx2: SIMPLE (Xb, unsigned char); break;
 | 
			
		||||
      case XbCOND: SIMPLE (XbCOND, unsigned char); break;
 | 
			
		||||
      case XG: SIMPLE (XG, nn_guid_t); break;
 | 
			
		||||
      case XbPROP: SIMPLE (XbPROP, unsigned char); break;
 | 
			
		||||
      case XG: SIMPLE (XG, ddsi_guid_t); break;
 | 
			
		||||
      case XK: SIMPLE (XK, nn_keyhash_t); break;
 | 
			
		||||
      case XQ: COMPLEX (XQ, ddsi_octetseq_t, if (x->length) {
 | 
			
		||||
        const size_t elem_size = ser_generic_srcsize (desc + 1);
 | 
			
		||||
        if (gen_seq_aliased)
 | 
			
		||||
        {
 | 
			
		||||
          /* The memory for the elements of a generic sequence are owned by the plist, the only aliased bits
 | 
			
		||||
             are the strings (XS) and octet sequences (XO) embedded in the elements.  So in principle, an
 | 
			
		||||
             unalias operation on a generic sequence should only operate on the elements of the sequence,
 | 
			
		||||
             not on the sequence buffer itself.
 | 
			
		||||
 | 
			
		||||
             However, the "mergein_missing" operation (and consequently the copy & dup operations) memcpy the
 | 
			
		||||
             source, then pretend it is aliased.  In this case, the sequence buffer is aliased, rather than
 | 
			
		||||
             private, and hence a new copy needs to be allocated. */
 | 
			
		||||
          x->value = ddsrt_memdup (x->value, x->length * elem_size);
 | 
			
		||||
        }
 | 
			
		||||
        for (uint32_t i = 0; i < x->length; i++) {
 | 
			
		||||
          size_t elem_off = i * elem_size;
 | 
			
		||||
          unalias_generic (x->value, &elem_off, gen_seq_aliased, desc + 1);
 | 
			
		||||
        }
 | 
			
		||||
      }); while (*++desc != XSTOP) { } break;
 | 
			
		||||
      case Xopt: break;
 | 
			
		||||
    }
 | 
			
		||||
    desc++;
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -739,13 +886,19 @@ static dds_return_t unalias_generic (void * __restrict dst, size_t * __restrict
 | 
			
		|||
#undef COMPLEX
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dds_return_t plist_unalias_generic (void * __restrict dst, const enum pserop * __restrict desc)
 | 
			
		||||
{
 | 
			
		||||
  size_t dstoff = 0;
 | 
			
		||||
  return unalias_generic (dst, &dstoff, false, desc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool unalias_generic_required (const enum pserop * __restrict desc)
 | 
			
		||||
{
 | 
			
		||||
  while (*desc != XSTOP)
 | 
			
		||||
  {
 | 
			
		||||
    switch (*desc++)
 | 
			
		||||
    {
 | 
			
		||||
      case XO: case XS: case XZ:
 | 
			
		||||
      case XO: case XS: case XQ:
 | 
			
		||||
        return true;
 | 
			
		||||
      default:
 | 
			
		||||
        break;
 | 
			
		||||
| 
						 | 
				
			
			@ -762,10 +915,16 @@ static bool fini_generic_required (const enum pserop * __restrict desc)
 | 
			
		|||
 | 
			
		||||
static dds_return_t fini_generic (void * __restrict dst, size_t * __restrict dstoff, struct flagset *flagset, uint64_t flag, const enum pserop * __restrict desc)
 | 
			
		||||
{
 | 
			
		||||
  fini_generic_partial (dst, dstoff, desc, NULL, *flagset->aliased & flag);
 | 
			
		||||
  fini_generic_embeddable (dst, dstoff, desc, NULL, *flagset->aliased & flag);
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void plist_fini_generic (void * __restrict dst, const enum pserop *desc, bool aliased)
 | 
			
		||||
{
 | 
			
		||||
  size_t dstoff = 0;
 | 
			
		||||
  fini_generic_embeddable (dst, &dstoff, desc, NULL, aliased);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static dds_return_t valid_generic (const void *src, size_t srcoff, const enum pserop * __restrict desc)
 | 
			
		||||
{
 | 
			
		||||
#define COMPLEX(basecase_, type_, cond_stmts_) do {                     \
 | 
			
		||||
| 
						 | 
				
			
			@ -783,23 +942,29 @@ static dds_return_t valid_generic (const void *src, size_t srcoff, const enum ps
 | 
			
		|||
      case XSTOP: return 0;
 | 
			
		||||
      case XO: SIMPLE (XO, ddsi_octetseq_t, (x->length == 0) == (x->value == NULL)); break;
 | 
			
		||||
      case XS: SIMPLE (XS, const char *, *x != NULL); break;
 | 
			
		||||
      case XZ: COMPLEX (XZ, ddsi_stringseq_t, {
 | 
			
		||||
        if ((x->n == 0) != (x->strs == NULL))
 | 
			
		||||
          return DDS_RETCODE_BAD_PARAMETER;
 | 
			
		||||
        for (uint32_t i = 0; i < x->n; i++)
 | 
			
		||||
          if (x->strs[i] == NULL)
 | 
			
		||||
            return DDS_RETCODE_BAD_PARAMETER;
 | 
			
		||||
      }); break;
 | 
			
		||||
      case XE1: case XE2: case XE3: SIMPLE (*desc, unsigned, *x <= 1 + (unsigned) *desc - XE1); break;
 | 
			
		||||
      case Xi: case Xix2: case Xix3: case Xix4: TRIVIAL (Xi, int32_t); break;
 | 
			
		||||
      case Xu: case Xux2: case Xux3: case Xux4: case Xux5: TRIVIAL (Xu, uint32_t); break;
 | 
			
		||||
      case Xl: SIMPLE (Xl, int32_t, *x == DDS_LENGTH_UNLIMITED || *x > 1); break;
 | 
			
		||||
      case XD: case XDx2: SIMPLE (XD, dds_duration_t, *x >= 0); break;
 | 
			
		||||
      case Xo: case Xox2: TRIVIAL (Xo, unsigned char); break;
 | 
			
		||||
      case Xb: case Xbx2: SIMPLE (Xb, unsigned char, *x == 0 || *x == 1); break;
 | 
			
		||||
      case XbCOND: SIMPLE (XbCOND, unsigned char, *x == 0 || *x == 1); break;
 | 
			
		||||
      case XG: TRIVIAL (XG, nn_guid_t); break;
 | 
			
		||||
      case XbPROP: SIMPLE (XbPROP, unsigned char, *x == 0 || *x == 1); break;
 | 
			
		||||
      case XG: TRIVIAL (XG, ddsi_guid_t); break;
 | 
			
		||||
      case XK: TRIVIAL (XK, nn_keyhash_t); break;
 | 
			
		||||
      case XQ: COMPLEX (XQ, ddsi_octetseq_t, {
 | 
			
		||||
        if ((x->length == 0) != (x->value == NULL))
 | 
			
		||||
          return DDS_RETCODE_BAD_PARAMETER;
 | 
			
		||||
        if (x->length) {
 | 
			
		||||
          const size_t elem_size = ser_generic_srcsize (desc + 1);
 | 
			
		||||
          dds_return_t ret;
 | 
			
		||||
          for (uint32_t i = 0; i < x->length; i++) {
 | 
			
		||||
            if ((ret = valid_generic (x->value, i * elem_size, desc + 1)) != 0)
 | 
			
		||||
              return ret;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }); while (*++desc != XSTOP) { } break;
 | 
			
		||||
      case Xopt: break;
 | 
			
		||||
    }
 | 
			
		||||
    desc++;
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -833,19 +998,9 @@ static bool equal_generic (const void *srcx, const void *srcy, size_t srcoff, co
 | 
			
		|||
      case XS:
 | 
			
		||||
        SIMPLE (XS, const char *, strcmp (*x, *y) == 0);
 | 
			
		||||
        break;
 | 
			
		||||
      case XZ:
 | 
			
		||||
        COMPLEX (XZ, ddsi_stringseq_t, {
 | 
			
		||||
          if (x->n != y->n)
 | 
			
		||||
            return false;
 | 
			
		||||
          for (uint32_t i = 0; i < x->n; i++)
 | 
			
		||||
            if (strcmp (x->strs[i], y->strs[i]) != 0)
 | 
			
		||||
              return false;
 | 
			
		||||
        });
 | 
			
		||||
        break;
 | 
			
		||||
      case XE1: case XE2: case XE3: TRIVIAL (*desc, unsigned); break;
 | 
			
		||||
      case Xi: case Xix2: case Xix3: case Xix4: TRIVIAL (Xi, int32_t); break;
 | 
			
		||||
      case Xu: case Xux2: case Xux3: case Xux4: case Xux5: TRIVIAL (Xu, uint32_t); break;
 | 
			
		||||
      case Xl: TRIVIAL (Xl, int32_t); break;
 | 
			
		||||
      case XD: case XDx2: TRIVIAL (XD, dds_duration_t); break;
 | 
			
		||||
      case Xo: case Xox2: TRIVIAL (Xo, unsigned char); break;
 | 
			
		||||
      case Xb: case Xbx2: TRIVIAL (Xb, unsigned char); break;
 | 
			
		||||
| 
						 | 
				
			
			@ -857,8 +1012,21 @@ static bool equal_generic (const void *srcx, const void *srcy, size_t srcoff, co
 | 
			
		|||
            return true;
 | 
			
		||||
        });
 | 
			
		||||
        break;
 | 
			
		||||
      case XG: SIMPLE (XG, nn_guid_t, memcmp (x, y, sizeof (*x))); break;
 | 
			
		||||
      case XK: SIMPLE (XK, nn_keyhash_t, memcmp (x, y, sizeof (*x))); break;
 | 
			
		||||
      case XbPROP: TRIVIAL (XbPROP, unsigned char); break;
 | 
			
		||||
      case XG: SIMPLE (XG, ddsi_guid_t, memcmp (x, y, sizeof (*x)) == 0); break;
 | 
			
		||||
      case XK: SIMPLE (XK, nn_keyhash_t, memcmp (x, y, sizeof (*x)) == 0); break;
 | 
			
		||||
      case XQ: COMPLEX (XQ, ddsi_octetseq_t, {
 | 
			
		||||
        if (x->length != y->length)
 | 
			
		||||
          return false;
 | 
			
		||||
        if (x->length) {
 | 
			
		||||
          const size_t elem_size = ser_generic_srcsize (desc + 1);
 | 
			
		||||
          for (uint32_t i = 0; i < x->length; i++) {
 | 
			
		||||
            if (!equal_generic (x->value, y->value, i * elem_size, desc + 1))
 | 
			
		||||
              return false;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }); while (*++desc != XSTOP) { } break;
 | 
			
		||||
      case Xopt: break;
 | 
			
		||||
    }
 | 
			
		||||
    desc++;
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -867,6 +1035,11 @@ static bool equal_generic (const void *srcx, const void *srcy, size_t srcoff, co
 | 
			
		|||
#undef COMPLEX
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool plist_equal_generic (const void *srcx, const void *srcy, const enum pserop * __restrict desc)
 | 
			
		||||
{
 | 
			
		||||
  return equal_generic (srcx, srcy, 0, desc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define membersize(type, member) sizeof (((type *) 0)->member)
 | 
			
		||||
#define ENTRY(PFX_, NAME_, member_, flag_, validate_, ...)                               \
 | 
			
		||||
  { PID_##NAME_, flag_, PFX_##_##NAME_, #NAME_, offsetof (struct nn_plist, member_),     \
 | 
			
		||||
| 
						 | 
				
			
			@ -904,7 +1077,7 @@ static dds_return_t dvx_resource_limits (void * __restrict dst, const struct dd
 | 
			
		|||
 | 
			
		||||
static dds_return_t dvx_participant_guid (void * __restrict dst, const struct dd * __restrict dd)
 | 
			
		||||
{
 | 
			
		||||
  const nn_guid_t *g = dst;
 | 
			
		||||
  const ddsi_guid_t *g = dst;
 | 
			
		||||
  (void) dd;
 | 
			
		||||
  if (g->prefix.u[0] == 0 && g->prefix.u[1] == 0 && g->prefix.u[2] == 0)
 | 
			
		||||
    return (g->entityid.u == 0) ? 0 : DDS_RETCODE_BAD_PARAMETER;
 | 
			
		||||
| 
						 | 
				
			
			@ -914,7 +1087,7 @@ static dds_return_t dvx_participant_guid (void * __restrict dst, const struct dd
 | 
			
		|||
 | 
			
		||||
static dds_return_t dvx_group_guid (void * __restrict dst, const struct dd * __restrict dd)
 | 
			
		||||
{
 | 
			
		||||
  const nn_guid_t *g = dst;
 | 
			
		||||
  const ddsi_guid_t *g = dst;
 | 
			
		||||
  (void) dd;
 | 
			
		||||
  if (g->prefix.u[0] == 0 && g->prefix.u[1] == 0 && g->prefix.u[2] == 0)
 | 
			
		||||
    return (g->entityid.u == 0) ? 0 : DDS_RETCODE_BAD_PARAMETER;
 | 
			
		||||
| 
						 | 
				
			
			@ -924,7 +1097,7 @@ static dds_return_t dvx_group_guid (void * __restrict dst, const struct dd * __r
 | 
			
		|||
 | 
			
		||||
static dds_return_t dvx_endpoint_guid (void * __restrict dst, const struct dd * __restrict dd)
 | 
			
		||||
{
 | 
			
		||||
  nn_guid_t *g = dst;
 | 
			
		||||
  ddsi_guid_t *g = dst;
 | 
			
		||||
  if (g->prefix.u[0] == 0 && g->prefix.u[1] == 0 && g->prefix.u[2] == 0)
 | 
			
		||||
    return (g->entityid.u == 0) ? 0 : DDS_RETCODE_BAD_PARAMETER;
 | 
			
		||||
  switch (g->entityid.u & NN_ENTITYID_KIND_MASK)
 | 
			
		||||
| 
						 | 
				
			
			@ -951,6 +1124,7 @@ static dds_return_t dvx_reader_favours_ssm (void * __restrict dst, const struct
 | 
			
		|||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Standardized parameters -- QoS _MUST_ come first (nn_plist_init_tables verifies this) because
 | 
			
		||||
   it allows early-out when processing a dds_qos_t instead of an nn_plist_t */
 | 
			
		||||
static const struct piddesc piddesc_omg[] = {
 | 
			
		||||
| 
						 | 
				
			
			@ -966,6 +1140,9 @@ static const struct piddesc piddesc_omg[] = {
 | 
			
		|||
  QP  (DEADLINE,                            deadline, XD),
 | 
			
		||||
  QP  (LATENCY_BUDGET,                      latency_budget, XD),
 | 
			
		||||
  QP  (LIVELINESS,                          liveliness, XE2, XD),
 | 
			
		||||
  /* Property list used to be of type [(String,String]), security changed into ([String,String],Maybe [(String,[Word8])]),
 | 
			
		||||
     the "Xopt" here is to allow both forms on input, with an assumed empty second sequence if the old form was received */
 | 
			
		||||
  QP  (PROPERTY_LIST,                       property, XQ, XbPROP, XS, XS, XSTOP, Xopt, XQ, XbPROP, XS, XO, XSTOP),
 | 
			
		||||
  /* Reliability encoding does not follow the rules (best-effort/reliable map to 1/2 instead of 0/1 */
 | 
			
		||||
  { PID_RELIABILITY, PDF_QOS | PDF_FUNCTION, QP_RELIABILITY, "RELIABILITY",
 | 
			
		||||
    offsetof (struct nn_plist, qos.reliability), membersize (struct nn_plist, qos.reliability),
 | 
			
		||||
| 
						 | 
				
			
			@ -978,7 +1155,7 @@ static const struct piddesc piddesc_omg[] = {
 | 
			
		|||
  QP  (OWNERSHIP,                           ownership, XE1),
 | 
			
		||||
  QP  (OWNERSHIP_STRENGTH,                  ownership_strength, Xi),
 | 
			
		||||
  QP  (PRESENTATION,                        presentation, XE2, Xbx2),
 | 
			
		||||
  QP  (PARTITION,                           partition, XZ),
 | 
			
		||||
  QP  (PARTITION,                           partition, XQ, XS, XSTOP),
 | 
			
		||||
  QP  (TIME_BASED_FILTER,                   time_based_filter, XD),
 | 
			
		||||
  QP  (TRANSPORT_PRIORITY,                  transport_priority, Xi),
 | 
			
		||||
  PP  (PROTOCOL_VERSION,                    protocol_version, Xox2),
 | 
			
		||||
| 
						 | 
				
			
			@ -1038,7 +1215,7 @@ static const struct piddesc piddesc_eclipse[] = {
 | 
			
		|||
  QP  (PRISMTECH_READER_LIFESPAN,           reader_lifespan, Xb, XD),
 | 
			
		||||
  QP  (PRISMTECH_WRITER_DATA_LIFECYCLE,     writer_data_lifecycle, Xb),
 | 
			
		||||
  QP  (PRISMTECH_READER_DATA_LIFECYCLE,     reader_data_lifecycle, XDx2),
 | 
			
		||||
  QP  (PRISMTECH_SUBSCRIPTION_KEYS,         subscription_keys, XbCOND, XZ),
 | 
			
		||||
  QP  (PRISMTECH_SUBSCRIPTION_KEYS,         subscription_keys, XbCOND, XQ, XS, XSTOP),
 | 
			
		||||
  { PID_PAD, PDF_QOS, QP_CYCLONE_IGNORELOCAL, "CYCLONE_IGNORELOCAL",
 | 
			
		||||
    offsetof (struct nn_plist, qos.ignorelocal), membersize (struct nn_plist, qos.ignorelocal),
 | 
			
		||||
    { .desc = { XE2, XSTOP } }, 0 },
 | 
			
		||||
| 
						 | 
				
			
			@ -1057,7 +1234,7 @@ static const struct piddesc piddesc_prismtech[] = {
 | 
			
		|||
  QP  (PRISMTECH_READER_LIFESPAN,           reader_lifespan, Xb, XD),
 | 
			
		||||
  QP  (PRISMTECH_WRITER_DATA_LIFECYCLE,     writer_data_lifecycle, Xb),
 | 
			
		||||
  QP  (PRISMTECH_READER_DATA_LIFECYCLE,     reader_data_lifecycle, XDx2),
 | 
			
		||||
  QP  (PRISMTECH_SUBSCRIPTION_KEYS,         subscription_keys, XbCOND, XZ),
 | 
			
		||||
  QP  (PRISMTECH_SUBSCRIPTION_KEYS,         subscription_keys, XbCOND, XQ, XS, XSTOP),
 | 
			
		||||
  PP  (PRISMTECH_BUILTIN_ENDPOINT_SET,      prismtech_builtin_endpoint_set, Xu),
 | 
			
		||||
  PP  (PRISMTECH_PARTICIPANT_VERSION_INFO,  prismtech_participant_version_info, Xux5, XS),
 | 
			
		||||
  PP  (PRISMTECH_EXEC_NAME,                 exec_name, XS),
 | 
			
		||||
| 
						 | 
				
			
			@ -1141,8 +1318,8 @@ static const struct piddesc_index piddesc_vendor_index[] = {
 | 
			
		|||
/* List of entries that require unalias, fini processing;
 | 
			
		||||
   initialized by nn_plist_init_tables; will assert when
 | 
			
		||||
   table too small or too large */
 | 
			
		||||
static const struct piddesc *piddesc_unalias[18];
 | 
			
		||||
static const struct piddesc *piddesc_fini[18];
 | 
			
		||||
static const struct piddesc *piddesc_unalias[19];
 | 
			
		||||
static const struct piddesc *piddesc_fini[19];
 | 
			
		||||
static ddsrt_once_t table_init_control = DDSRT_ONCE_INIT;
 | 
			
		||||
 | 
			
		||||
static nn_parameterid_t pid_without_flags (nn_parameterid_t pid)
 | 
			
		||||
| 
						 | 
				
			
			@ -1268,7 +1445,7 @@ static void plist_or_xqos_fini (void * __restrict dst, size_t shift, uint64_t pm
 | 
			
		|||
  if (shift > 0)
 | 
			
		||||
  {
 | 
			
		||||
    dds_qos_t *qos = dst;
 | 
			
		||||
    pfs = (struct flagset) { 0 };
 | 
			
		||||
    pfs = (struct flagset) { NULL, NULL, 0 };
 | 
			
		||||
    qfs = (struct flagset) { .present = &qos->present, .aliased = &qos->aliased };
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
| 
						 | 
				
			
			@ -1310,7 +1487,7 @@ static void plist_or_xqos_unalias (void * __restrict dst, size_t shift)
 | 
			
		|||
  if (shift > 0)
 | 
			
		||||
  {
 | 
			
		||||
    dds_qos_t *qos = dst;
 | 
			
		||||
    pfs = (struct flagset) { 0 };
 | 
			
		||||
    pfs = (struct flagset) { NULL, NULL, 0 };
 | 
			
		||||
    qfs = (struct flagset) { .present = &qos->present, .aliased = &qos->aliased };
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
| 
						 | 
				
			
			@ -1331,7 +1508,7 @@ static void plist_or_xqos_unalias (void * __restrict dst, size_t shift)
 | 
			
		|||
    if ((*fs->present & entry->present_flag) && (*fs->aliased & entry->present_flag))
 | 
			
		||||
    {
 | 
			
		||||
      if (!(entry->flags & PDF_FUNCTION))
 | 
			
		||||
        unalias_generic (dst, &dstoff, entry->op.desc);
 | 
			
		||||
        unalias_generic (dst, &dstoff, false, entry->op.desc);
 | 
			
		||||
      else if (entry->op.f.unalias)
 | 
			
		||||
        entry->op.f.unalias (dst, &dstoff);
 | 
			
		||||
      *fs->aliased &= ~entry->present_flag;
 | 
			
		||||
| 
						 | 
				
			
			@ -1354,9 +1531,9 @@ static void plist_or_xqos_mergein_missing (void * __restrict dst, const void * _
 | 
			
		|||
  {
 | 
			
		||||
    dds_qos_t *qos_dst = dst;
 | 
			
		||||
    const dds_qos_t *qos_src = src;
 | 
			
		||||
    pfs_dst = (struct flagset) { 0 };
 | 
			
		||||
    pfs_dst = (struct flagset) { NULL, NULL, 0 };
 | 
			
		||||
    qfs_dst = (struct flagset) { .present = &qos_dst->present, .aliased = &qos_dst->aliased };
 | 
			
		||||
    pfs_src = (struct flagset) { 0 };
 | 
			
		||||
    pfs_src = (struct flagset) { NULL, NULL, 0 };
 | 
			
		||||
    qfs_src = (struct flagset) { .present = (uint64_t *) &qos_src->present, .aliased = (uint64_t *) &qos_src->aliased };
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
| 
						 | 
				
			
			@ -1389,15 +1566,15 @@ static void plist_or_xqos_mergein_missing (void * __restrict dst, const void * _
 | 
			
		|||
      if (!(*fs_dst->present & entry->present_flag) && (*fs_src->present & mask & entry->present_flag))
 | 
			
		||||
      {
 | 
			
		||||
        /* bitwise copy, mark as aliased & unalias; have to unalias fields one-by-one rather than
 | 
			
		||||
         do this for all fields and call "unalias" on the entire object because fields that are
 | 
			
		||||
         already present may be aliased, and it would be somewhat impolite to change that.
 | 
			
		||||
           do this for all fields and call "unalias" on the entire object because fields that are
 | 
			
		||||
           already present may be aliased, and it would be somewhat impolite to change that.
 | 
			
		||||
 | 
			
		||||
         Note: dst & src have the same type, so offset in src is the same;
 | 
			
		||||
         Note: unalias may have to look at */
 | 
			
		||||
           Note: dst & src have the same type, so offset in src is the same;
 | 
			
		||||
           Note: unalias may have to look at */
 | 
			
		||||
        memcpy ((char *) dst + dstoff, (const char *) src + dstoff, entry->size);
 | 
			
		||||
        *fs_dst->present |= entry->present_flag;
 | 
			
		||||
        if (!(entry->flags & PDF_FUNCTION))
 | 
			
		||||
          unalias_generic (dst, &dstoff, entry->op.desc);
 | 
			
		||||
          unalias_generic (dst, &dstoff, true, entry->op.desc);
 | 
			
		||||
        else if (entry->op.f.unalias)
 | 
			
		||||
          entry->op.f.unalias (dst, &dstoff);
 | 
			
		||||
      }
 | 
			
		||||
| 
						 | 
				
			
			@ -2228,7 +2405,7 @@ const unsigned char *nn_plist_findparam_native_unchecked (const void *src, nn_pa
 | 
			
		|||
  const nn_parameter_t *par = src;
 | 
			
		||||
  while (par->parameterid != pid)
 | 
			
		||||
  {
 | 
			
		||||
    if (pid == PID_SENTINEL)
 | 
			
		||||
    if (par->parameterid == PID_SENTINEL)
 | 
			
		||||
      return NULL;
 | 
			
		||||
    par = (const nn_parameter_t *) ((const char *) (par + 1) + par->length);
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -2763,6 +2940,29 @@ void nn_log_xqos (uint32_t cat, const struct ddsrt_log_cfg *logcfg, const dds_qo
 | 
			
		|||
  });
 | 
			
		||||
  DO (PRISMTECH_ENTITY_FACTORY, { LOGB1 ("entity_factory=%u", xqos->entity_factory.autoenable_created_entities); });
 | 
			
		||||
  DO (CYCLONE_IGNORELOCAL, { LOGB1 ("ignorelocal=%u", xqos->ignorelocal.value); });
 | 
			
		||||
  DO (PROPERTY_LIST, {
 | 
			
		||||
    LOGB0 ("property_list={");
 | 
			
		||||
    DDS_CLOG (cat, logcfg, "value={");
 | 
			
		||||
    for (uint32_t i = 0; i < xqos->property.value.n; i++) {
 | 
			
		||||
      DDS_CLOG (cat, logcfg, "%s{%s,%s,%u}",
 | 
			
		||||
                                      (i == 0) ? "" : ",",
 | 
			
		||||
                                      xqos->property.value.props[i].name,
 | 
			
		||||
                                      xqos->property.value.props[i].value,
 | 
			
		||||
                                      xqos->property.value.props[i].propagate);
 | 
			
		||||
    }
 | 
			
		||||
    DDS_CLOG (cat, logcfg, "}");
 | 
			
		||||
    DDS_CLOG (cat, logcfg, "binary_value={");
 | 
			
		||||
    for (uint32_t i = 0; i < xqos->property.binary_value.n; i++) {
 | 
			
		||||
      DDS_CLOG (cat, logcfg, "%s{%s,(%u,%p),%u}",
 | 
			
		||||
                                      (i == 0) ? "" : ",",
 | 
			
		||||
                                      xqos->property.binary_value.props[i].name,
 | 
			
		||||
                                      xqos->property.binary_value.props[i].value.length,
 | 
			
		||||
                                      xqos->property.binary_value.props[i].value.value,
 | 
			
		||||
                                      xqos->property.binary_value.props[i].propagate);
 | 
			
		||||
    }
 | 
			
		||||
    DDS_CLOG (cat, logcfg, "}");
 | 
			
		||||
    DDS_CLOG (cat, logcfg, "}");
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
#undef PRINTARG_DUR
 | 
			
		||||
#undef FMT_DUR
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2407,7 +2407,7 @@ struct nn_dqueue_bubble {
 | 
			
		|||
      void *arg;
 | 
			
		||||
    } cb;
 | 
			
		||||
    struct {
 | 
			
		||||
      nn_guid_t rdguid;
 | 
			
		||||
      ddsi_guid_t rdguid;
 | 
			
		||||
      uint32_t count;
 | 
			
		||||
    } rdguid;
 | 
			
		||||
  } u;
 | 
			
		||||
| 
						 | 
				
			
			@ -2429,7 +2429,7 @@ static uint32_t dqueue_thread (struct nn_dqueue *q)
 | 
			
		|||
  struct q_globals const * const gv = ddsrt_atomic_ldvoidp (&ts1->gv);
 | 
			
		||||
  nn_mtime_t next_thread_cputime = { 0 };
 | 
			
		||||
  int keepgoing = 1;
 | 
			
		||||
  nn_guid_t rdguid, *prdguid = NULL;
 | 
			
		||||
  ddsi_guid_t rdguid, *prdguid = NULL;
 | 
			
		||||
  uint32_t rdguid_count = 0;
 | 
			
		||||
 | 
			
		||||
  ddsrt_mutex_lock (&q->lock);
 | 
			
		||||
| 
						 | 
				
			
			@ -2631,7 +2631,7 @@ void nn_dqueue_enqueue_callback (struct nn_dqueue *q, nn_dqueue_callback_t cb, v
 | 
			
		|||
  nn_dqueue_enqueue_bubble (q, b);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nn_dqueue_enqueue1 (struct nn_dqueue *q, const nn_guid_t *rdguid, struct nn_rsample_chain *sc, nn_reorder_result_t rres)
 | 
			
		||||
void nn_dqueue_enqueue1 (struct nn_dqueue *q, const ddsi_guid_t *rdguid, struct nn_rsample_chain *sc, nn_reorder_result_t rres)
 | 
			
		||||
{
 | 
			
		||||
  struct nn_dqueue_bubble *b;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -44,7 +44,7 @@
 | 
			
		|||
#include "dds/ddsi/q_entity.h"
 | 
			
		||||
#include "dds/ddsi/q_xmsg.h"
 | 
			
		||||
#include "dds/ddsi/q_receive.h"
 | 
			
		||||
#include "dds/ddsi/q_rhc.h"
 | 
			
		||||
#include "dds/ddsi/ddsi_rhc.h"
 | 
			
		||||
 | 
			
		||||
#include "dds/ddsi/q_transmit.h"
 | 
			
		||||
#include "dds/ddsi/q_globals.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -74,7 +74,7 @@ Notes:
 | 
			
		|||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
static void deliver_user_data_synchronously (struct nn_rsample_chain *sc, const nn_guid_t *rdguid);
 | 
			
		||||
static void deliver_user_data_synchronously (struct nn_rsample_chain *sc, const ddsi_guid_t *rdguid);
 | 
			
		||||
 | 
			
		||||
static void maybe_set_reader_in_sync (struct proxy_writer *pwr, struct pwr_rd_match *wn, seqno_t last_deliv_seq)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -285,7 +285,7 @@ static int valid_NackFrag (NackFrag_t *msg, size_t size, int byteswap)
 | 
			
		|||
  return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void set_sampleinfo_proxy_writer (struct nn_rsample_info *sampleinfo, nn_guid_t *pwr_guid)
 | 
			
		||||
static void set_sampleinfo_proxy_writer (struct nn_rsample_info *sampleinfo, ddsi_guid_t *pwr_guid)
 | 
			
		||||
{
 | 
			
		||||
  struct proxy_writer * pwr = ephash_lookup_proxy_writer_guid (sampleinfo->rst->gv->guid_hash, pwr_guid);
 | 
			
		||||
  sampleinfo->pwr = pwr;
 | 
			
		||||
| 
						 | 
				
			
			@ -294,7 +294,7 @@ static void set_sampleinfo_proxy_writer (struct nn_rsample_info *sampleinfo, nn_
 | 
			
		|||
static int valid_Data (const struct receiver_state *rst, struct nn_rmsg *rmsg, Data_t *msg, size_t size, int byteswap, struct nn_rsample_info *sampleinfo, unsigned char **payloadp)
 | 
			
		||||
{
 | 
			
		||||
  /* on success: sampleinfo->{seq,rst,statusinfo,pt_wr_info_zoff,bswap,complex_qos} all set */
 | 
			
		||||
  nn_guid_t pwr_guid;
 | 
			
		||||
  ddsi_guid_t pwr_guid;
 | 
			
		||||
  unsigned char *ptr;
 | 
			
		||||
 | 
			
		||||
  if (size < sizeof (*msg))
 | 
			
		||||
| 
						 | 
				
			
			@ -405,7 +405,7 @@ static int valid_DataFrag (const struct receiver_state *rst, struct nn_rmsg *rms
 | 
			
		|||
{
 | 
			
		||||
  /* on success: sampleinfo->{rst,statusinfo,pt_wr_info_zoff,bswap,complex_qos} all set */
 | 
			
		||||
  uint32_t payloadsz;
 | 
			
		||||
  nn_guid_t pwr_guid;
 | 
			
		||||
  ddsi_guid_t pwr_guid;
 | 
			
		||||
  unsigned char *ptr;
 | 
			
		||||
 | 
			
		||||
  if (size < sizeof (*msg))
 | 
			
		||||
| 
						 | 
				
			
			@ -628,7 +628,7 @@ static int handle_AckNack (struct receiver_state *rst, nn_etime_t tnow, const Ac
 | 
			
		|||
  struct proxy_reader *prd;
 | 
			
		||||
  struct wr_prd_match *rn;
 | 
			
		||||
  struct writer *wr;
 | 
			
		||||
  nn_guid_t src, dst;
 | 
			
		||||
  ddsi_guid_t src, dst;
 | 
			
		||||
  seqno_t seqbase;
 | 
			
		||||
  seqno_t seq_xmit;
 | 
			
		||||
  nn_count_t *countp;
 | 
			
		||||
| 
						 | 
				
			
			@ -991,7 +991,7 @@ static int handle_AckNack (struct receiver_state *rst, nn_etime_t tnow, const Ac
 | 
			
		|||
  return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_forall_destinations (const nn_guid_t *dst, struct proxy_writer *pwr, ddsrt_avl_walk_t fun, void *arg)
 | 
			
		||||
static void handle_forall_destinations (const ddsi_guid_t *dst, struct proxy_writer *pwr, ddsrt_avl_walk_t fun, void *arg)
 | 
			
		||||
{
 | 
			
		||||
  /* prefix:  id:   to:
 | 
			
		||||
     0        0     all matched readers
 | 
			
		||||
| 
						 | 
				
			
			@ -1023,7 +1023,7 @@ static void handle_forall_destinations (const nn_guid_t *dst, struct proxy_write
 | 
			
		|||
      break;
 | 
			
		||||
    case (1 << 1) | 0: /* all within one participant: walk a range of keyvalues */
 | 
			
		||||
      {
 | 
			
		||||
        nn_guid_t a, b;
 | 
			
		||||
        ddsi_guid_t a, b;
 | 
			
		||||
        a = *dst; a.entityid.u = 0;
 | 
			
		||||
        b = *dst; b.entityid.u = ~0u;
 | 
			
		||||
        ddsrt_avl_walk_range (&pwr_readers_treedef, &pwr->readers, &a, &b, fun, arg);
 | 
			
		||||
| 
						 | 
				
			
			@ -1071,7 +1071,7 @@ static void handle_Heartbeat_helper (struct pwr_rd_match * const wn, struct hand
 | 
			
		|||
    refseq = nn_reorder_next_seq (pwr->reorder) - 1;
 | 
			
		||||
  else
 | 
			
		||||
    refseq = nn_reorder_next_seq (wn->u.not_in_sync.reorder) - 1;
 | 
			
		||||
    RSTTRACE (" "PGUIDFMT"@%"PRId64"%s", PGUID (wn->rd_guid), refseq, (wn->in_sync == PRMSS_SYNC) ? "(sync)" : (wn->in_sync == PRMSS_TLCATCHUP) ? "(tlcatchup)" : "");
 | 
			
		||||
  RSTTRACE (" "PGUIDFMT"@%"PRId64"%s", PGUID (wn->rd_guid), refseq, (wn->in_sync == PRMSS_SYNC) ? "(sync)" : (wn->in_sync == PRMSS_TLCATCHUP) ? "(tlcatchup)" : "");
 | 
			
		||||
 | 
			
		||||
  /* Reschedule AckNack transmit if deemed appropriate; unreliable
 | 
			
		||||
     readers have acknack_xevent == NULL and can't do this.
 | 
			
		||||
| 
						 | 
				
			
			@ -1124,7 +1124,7 @@ static int handle_Heartbeat (struct receiver_state *rst, nn_etime_t tnow, struct
 | 
			
		|||
  const seqno_t lastseq = fromSN (msg->lastSN);
 | 
			
		||||
  struct handle_Heartbeat_helper_arg arg;
 | 
			
		||||
  struct proxy_writer *pwr;
 | 
			
		||||
  nn_guid_t src, dst;
 | 
			
		||||
  ddsi_guid_t src, dst;
 | 
			
		||||
 | 
			
		||||
  src.prefix = rst->src_guid_prefix;
 | 
			
		||||
  src.entityid = msg->writerId;
 | 
			
		||||
| 
						 | 
				
			
			@ -1261,7 +1261,7 @@ static int handle_HeartbeatFrag (struct receiver_state *rst, UNUSED_ARG(nn_etime
 | 
			
		|||
{
 | 
			
		||||
  const seqno_t seq = fromSN (msg->writerSN);
 | 
			
		||||
  const nn_fragment_number_t fragnum = msg->lastFragmentNum - 1; /* we do 0-based */
 | 
			
		||||
  nn_guid_t src, dst;
 | 
			
		||||
  ddsi_guid_t src, dst;
 | 
			
		||||
  struct proxy_writer *pwr;
 | 
			
		||||
 | 
			
		||||
  src.prefix = rst->src_guid_prefix;
 | 
			
		||||
| 
						 | 
				
			
			@ -1374,7 +1374,7 @@ static int handle_NackFrag (struct receiver_state *rst, nn_etime_t tnow, const N
 | 
			
		|||
  struct wr_prd_match *rn;
 | 
			
		||||
  struct writer *wr;
 | 
			
		||||
  struct whc_borrowed_sample sample;
 | 
			
		||||
  nn_guid_t src, dst;
 | 
			
		||||
  ddsi_guid_t src, dst;
 | 
			
		||||
  nn_count_t *countp;
 | 
			
		||||
  seqno_t seq = fromSN (msg->writerSN);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1490,7 +1490,7 @@ static int handle_NackFrag (struct receiver_state *rst, nn_etime_t tnow, const N
 | 
			
		|||
  return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int handle_InfoDST (struct receiver_state *rst, const InfoDST_t *msg, const nn_guid_prefix_t *dst_prefix)
 | 
			
		||||
static int handle_InfoDST (struct receiver_state *rst, const InfoDST_t *msg, const ddsi_guid_prefix_t *dst_prefix)
 | 
			
		||||
{
 | 
			
		||||
  rst->dst_guid_prefix = nn_ntoh_guid_prefix (msg->guid_prefix);
 | 
			
		||||
  RSTTRACE ("INFODST(%"PRIx32":%"PRIx32":%"PRIx32")", PGUIDPREFIX (rst->dst_guid_prefix));
 | 
			
		||||
| 
						 | 
				
			
			@ -1502,7 +1502,7 @@ static int handle_InfoDST (struct receiver_state *rst, const InfoDST_t *msg, con
 | 
			
		|||
  }
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
    nn_guid_t dst;
 | 
			
		||||
    ddsi_guid_t dst;
 | 
			
		||||
    dst.prefix = rst->dst_guid_prefix;
 | 
			
		||||
    dst.entityid = to_entityid(NN_ENTITYID_PARTICIPANT);
 | 
			
		||||
    rst->forme = (ephash_lookup_participant_guid (rst->gv->guid_hash, &dst) != NULL ||
 | 
			
		||||
| 
						 | 
				
			
			@ -1623,7 +1623,7 @@ static int handle_Gap (struct receiver_state *rst, nn_etime_t tnow, struct nn_rm
 | 
			
		|||
 | 
			
		||||
  struct proxy_writer *pwr;
 | 
			
		||||
  struct pwr_rd_match *wn;
 | 
			
		||||
  nn_guid_t src, dst;
 | 
			
		||||
  ddsi_guid_t src, dst;
 | 
			
		||||
  seqno_t gapstart, listbase;
 | 
			
		||||
  int32_t last_included_rel;
 | 
			
		||||
  uint32_t listidx;
 | 
			
		||||
| 
						 | 
				
			
			@ -1739,16 +1739,10 @@ static struct ddsi_serdata *get_serdata (struct ddsi_sertopic const * const topi
 | 
			
		|||
  return sd;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct ddsi_serdata *extract_sample_from_data
 | 
			
		||||
(
 | 
			
		||||
  const struct nn_rsample_info *sampleinfo, unsigned char data_smhdr_flags,
 | 
			
		||||
  const nn_plist_t *qos, const struct nn_rdata *fragchain, unsigned statusinfo,
 | 
			
		||||
  nn_wctime_t tstamp, struct ddsi_sertopic const * const topic
 | 
			
		||||
)
 | 
			
		||||
static struct ddsi_serdata *new_sample_from_data (struct ddsi_tkmap_instance **tk1, struct q_globals *gv, const struct nn_rsample_info *sampleinfo, unsigned char data_smhdr_flags, const nn_plist_t *qos, const struct nn_rdata *fragchain, unsigned statusinfo, nn_wctime_t tstamp, struct ddsi_sertopic const * const topic)
 | 
			
		||||
{
 | 
			
		||||
  static const nn_guid_t null_guid = {{{0,0,0,0,0,0,0,0,0,0,0,0}},{0}};
 | 
			
		||||
  const char *failmsg = NULL;
 | 
			
		||||
  struct ddsi_serdata * sample = NULL;
 | 
			
		||||
  struct ddsi_serdata *sample = NULL;
 | 
			
		||||
 | 
			
		||||
  if (statusinfo == 0)
 | 
			
		||||
  {
 | 
			
		||||
| 
						 | 
				
			
			@ -1756,8 +1750,11 @@ static struct ddsi_serdata *extract_sample_from_data
 | 
			
		|||
    if (!(data_smhdr_flags & DATA_FLAG_DATAFLAG) || sampleinfo->size == 0)
 | 
			
		||||
    {
 | 
			
		||||
      const struct proxy_writer *pwr = sampleinfo->pwr;
 | 
			
		||||
      nn_guid_t guid = pwr ? pwr->e.guid : null_guid; /* can't be null _yet_, but that might change some day */
 | 
			
		||||
      DDS_CTRACE (&sampleinfo->rst->gv->logconfig,
 | 
			
		||||
      ddsi_guid_t guid;
 | 
			
		||||
      /* pwr can't currently be null, but that might change some day, and this being
 | 
			
		||||
         an error path, it doesn't hurt to survive that */
 | 
			
		||||
      if (pwr) guid = pwr->e.guid; else memset (&guid, 0, sizeof (guid));
 | 
			
		||||
      DDS_CTRACE (&gv->logconfig,
 | 
			
		||||
                  "data(application, vendor %u.%u): "PGUIDFMT" #%"PRId64": write without proper payload (data_smhdr_flags 0x%x size %"PRIu32")\n",
 | 
			
		||||
                  sampleinfo->rst->vendor.id[0], sampleinfo->rst->vendor.id[1],
 | 
			
		||||
                  PGUID (guid), sampleinfo->seq,
 | 
			
		||||
| 
						 | 
				
			
			@ -1785,7 +1782,7 @@ static struct ddsi_serdata *extract_sample_from_data
 | 
			
		|||
  {
 | 
			
		||||
    /* RTI always tries to make us survive on the keyhash. RTI must
 | 
			
		||||
       mend its ways. */
 | 
			
		||||
    if (NN_STRICT_P (sampleinfo->rst->gv->config))
 | 
			
		||||
    if (NN_STRICT_P (gv->config))
 | 
			
		||||
      failmsg = "no content";
 | 
			
		||||
    else if (!(qos->present & PP_KEYHASH))
 | 
			
		||||
      failmsg = "qos present but without keyhash";
 | 
			
		||||
| 
						 | 
				
			
			@ -1805,17 +1802,47 @@ static struct ddsi_serdata *extract_sample_from_data
 | 
			
		|||
  {
 | 
			
		||||
    /* No message => error out */
 | 
			
		||||
    const struct proxy_writer *pwr = sampleinfo->pwr;
 | 
			
		||||
    nn_guid_t guid = pwr ? pwr->e.guid : null_guid; /* can't be null _yet_, but that might change some day */
 | 
			
		||||
    DDS_CWARNING (&sampleinfo->rst->gv->logconfig,
 | 
			
		||||
    ddsi_guid_t guid;
 | 
			
		||||
    if (pwr) guid = pwr->e.guid; else memset (&guid, 0, sizeof (guid));
 | 
			
		||||
    DDS_CWARNING (&gv->logconfig,
 | 
			
		||||
                  "data(application, vendor %u.%u): "PGUIDFMT" #%"PRId64": deserialization %s/%s failed (%s)\n",
 | 
			
		||||
                  sampleinfo->rst->vendor.id[0], sampleinfo->rst->vendor.id[1],
 | 
			
		||||
                  PGUID (guid), sampleinfo->seq,
 | 
			
		||||
                  topic->name, topic->type_name,
 | 
			
		||||
                  failmsg ? failmsg : "for reasons unknown");
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
    if ((*tk1 = ddsi_tkmap_lookup_instance_ref (gv->m_tkmap, sample)) == NULL)
 | 
			
		||||
    {
 | 
			
		||||
      ddsi_serdata_unref (sample);
 | 
			
		||||
      sample = NULL;
 | 
			
		||||
    }
 | 
			
		||||
    else if (gv->logconfig.c.mask & DDS_LC_TRACE)
 | 
			
		||||
    {
 | 
			
		||||
      const struct proxy_writer *pwr = sampleinfo->pwr;
 | 
			
		||||
      ddsi_guid_t guid;
 | 
			
		||||
      char tmp[1024];
 | 
			
		||||
      size_t res = 0;
 | 
			
		||||
      tmp[0] = 0;
 | 
			
		||||
      if (gv->logconfig.c.mask & DDS_LC_CONTENT)
 | 
			
		||||
        res = ddsi_serdata_print (sample, tmp, sizeof (tmp));
 | 
			
		||||
      if (pwr) guid = pwr->e.guid; else memset (&guid, 0, sizeof (guid));
 | 
			
		||||
      GVTRACE ("data(application, vendor %u.%u): "PGUIDFMT" #%"PRId64": ST%x %s/%s:%s%s",
 | 
			
		||||
               sampleinfo->rst->vendor.id[0], sampleinfo->rst->vendor.id[1],
 | 
			
		||||
               PGUID (guid), sampleinfo->seq, statusinfo, topic->name, topic->type_name,
 | 
			
		||||
               tmp, res < sizeof (tmp) ? "" : "(trunc)");
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return sample;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void free_sample_after_store (struct q_globals *gv, struct ddsi_serdata *sample, struct ddsi_tkmap_instance *tk)
 | 
			
		||||
{
 | 
			
		||||
  ddsi_tkmap_instance_unref (gv->m_tkmap, tk);
 | 
			
		||||
  ddsi_serdata_unref (sample);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsigned char normalize_data_datafrag_flags (const SubmessageHeader_t *smhdr)
 | 
			
		||||
{
 | 
			
		||||
  switch ((SubmessageKind_t) smhdr->submessageId)
 | 
			
		||||
| 
						 | 
				
			
			@ -1837,17 +1864,36 @@ unsigned char normalize_data_datafrag_flags (const SubmessageHeader_t *smhdr)
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int deliver_user_data (const struct nn_rsample_info *sampleinfo, const struct nn_rdata *fragchain, const nn_guid_t *rdguid, int pwr_locked)
 | 
			
		||||
static struct reader *proxy_writer_first_in_sync_reader (struct proxy_writer *pwr, ddsrt_avl_iter_t *it)
 | 
			
		||||
{
 | 
			
		||||
  struct pwr_rd_match *m;
 | 
			
		||||
  struct reader *rd;
 | 
			
		||||
  for (m = ddsrt_avl_iter_first (&pwr_readers_treedef, &pwr->readers, it); m != NULL; m = ddsrt_avl_iter_next (it))
 | 
			
		||||
    if (m->in_sync == PRMSS_SYNC && (rd = ephash_lookup_reader_guid (pwr->e.gv->guid_hash, &m->rd_guid)) != NULL)
 | 
			
		||||
      return rd;
 | 
			
		||||
  return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct reader *proxy_writer_next_in_sync_reader (struct proxy_writer *pwr, ddsrt_avl_iter_t *it)
 | 
			
		||||
{
 | 
			
		||||
  struct pwr_rd_match *m;
 | 
			
		||||
  struct reader *rd;
 | 
			
		||||
  for (m = ddsrt_avl_iter_next (it); m != NULL; m = ddsrt_avl_iter_next (it))
 | 
			
		||||
    if (m->in_sync == PRMSS_SYNC && (rd = ephash_lookup_reader_guid (pwr->e.gv->guid_hash, &m->rd_guid)) != NULL)
 | 
			
		||||
      return rd;
 | 
			
		||||
  return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int deliver_user_data (const struct nn_rsample_info *sampleinfo, const struct nn_rdata *fragchain, const ddsi_guid_t *rdguid, int pwr_locked)
 | 
			
		||||
{
 | 
			
		||||
  struct receiver_state const * const rst = sampleinfo->rst;
 | 
			
		||||
  struct q_globals * const gv = rst->gv;
 | 
			
		||||
  struct proxy_writer * const pwr = sampleinfo->pwr;
 | 
			
		||||
  struct ddsi_sertopic const * const topic = pwr->c.topic;
 | 
			
		||||
  unsigned statusinfo;
 | 
			
		||||
  Data_DataFrag_common_t *msg;
 | 
			
		||||
  unsigned char data_smhdr_flags;
 | 
			
		||||
  nn_plist_t qos;
 | 
			
		||||
  int need_keyhash;
 | 
			
		||||
  struct ddsi_serdata * payload;
 | 
			
		||||
 | 
			
		||||
  if (pwr->ddsi2direct_cb)
 | 
			
		||||
  {
 | 
			
		||||
| 
						 | 
				
			
			@ -1855,22 +1901,11 @@ static int deliver_user_data (const struct nn_rsample_info *sampleinfo, const st
 | 
			
		|||
    return 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /* NOTE: pwr->e.lock need not be held for correct processing (though
 | 
			
		||||
     it may be useful to hold it for maintaining order all the way to
 | 
			
		||||
     v_groupWrite): guid is constant, set_vmsg_header() explains about
 | 
			
		||||
     the qos issue (and will have to deal with that); and
 | 
			
		||||
     pwr->groupset takes care of itself.  FIXME: groupset may be
 | 
			
		||||
     taking care of itself, but it is currently doing so in an
 | 
			
		||||
     annoyingly simplistic manner ...  */
 | 
			
		||||
 | 
			
		||||
  /* FIXME: fragments are now handled by copying the message to
 | 
			
		||||
     freshly malloced memory (see defragment()) ... that'll have to
 | 
			
		||||
     change eventually */
 | 
			
		||||
  assert (fragchain->min == 0);
 | 
			
		||||
  assert (!is_builtin_entityid (pwr->e.guid.entityid, pwr->c.vendor));
 | 
			
		||||
  /* Can only get here if at some point readers existed => topic can't
 | 
			
		||||
     still be NULL, even if there are no readers at the moment */
 | 
			
		||||
  assert (topic != NULL);
 | 
			
		||||
 | 
			
		||||
  /* Luckily, the Data header (up to inline QoS) is a prefix of the
 | 
			
		||||
     DataFrag header, so for the fixed-position things that we're
 | 
			
		||||
| 
						 | 
				
			
			@ -1906,81 +1941,65 @@ static int deliver_user_data (const struct nn_rsample_info *sampleinfo, const st
 | 
			
		|||
    src.encoding = (msg->smhdr.flags & SMFLAG_ENDIANNESS) ? PL_CDR_LE : PL_CDR_BE;
 | 
			
		||||
    src.buf = NN_RMSG_PAYLOADOFF (fragchain->rmsg, qos_offset);
 | 
			
		||||
    src.bufsz = NN_RDATA_PAYLOAD_OFF (fragchain) - qos_offset;
 | 
			
		||||
    src.strict = NN_STRICT_P (rst->gv->config);
 | 
			
		||||
    src.factory = rst->gv->m_factory;
 | 
			
		||||
    src.logconfig = &rst->gv->logconfig;
 | 
			
		||||
    src.strict = NN_STRICT_P (gv->config);
 | 
			
		||||
    src.factory = gv->m_factory;
 | 
			
		||||
    src.logconfig = &gv->logconfig;
 | 
			
		||||
    if ((plist_ret = nn_plist_init_frommsg (&qos, NULL, PP_STATUSINFO | PP_KEYHASH | PP_COHERENT_SET, 0, &src)) < 0)
 | 
			
		||||
    {
 | 
			
		||||
      if (plist_ret != DDS_RETCODE_UNSUPPORTED)
 | 
			
		||||
        DDS_CWARNING (&sampleinfo->rst->gv->logconfig,
 | 
			
		||||
                      "data(application, vendor %u.%u): "PGUIDFMT" #%"PRId64": invalid inline qos\n",
 | 
			
		||||
                      src.vendorid.id[0], src.vendorid.id[1], PGUID (pwr->e.guid), sampleinfo->seq);
 | 
			
		||||
        GVWARNING ("data(application, vendor %u.%u): "PGUIDFMT" #%"PRId64": invalid inline qos\n",
 | 
			
		||||
                   src.vendorid.id[0], src.vendorid.id[1], PGUID (pwr->e.guid), sampleinfo->seq);
 | 
			
		||||
      return 0;
 | 
			
		||||
    }
 | 
			
		||||
    statusinfo = (qos.present & PP_STATUSINFO) ? qos.statusinfo : 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /* Note: deserializing done potentially many times for a historical
 | 
			
		||||
     data sample (once per reader that cares about that data).  For
 | 
			
		||||
     now, this is accepted as sufficiently abnormal behaviour to not
 | 
			
		||||
     worry about it. */
 | 
			
		||||
  {
 | 
			
		||||
    nn_wctime_t tstamp;
 | 
			
		||||
    if (sampleinfo->timestamp.v != NN_WCTIME_INVALID.v)
 | 
			
		||||
      tstamp = sampleinfo->timestamp;
 | 
			
		||||
    else
 | 
			
		||||
      tstamp.v = 0;
 | 
			
		||||
    payload = extract_sample_from_data (sampleinfo, data_smhdr_flags, &qos, fragchain, statusinfo, tstamp, topic);
 | 
			
		||||
  }
 | 
			
		||||
  if (payload == NULL)
 | 
			
		||||
  {
 | 
			
		||||
    goto no_payload;
 | 
			
		||||
  }
 | 
			
		||||
  /* FIXME: should it be 0, local wall clock time or INVALID? */
 | 
			
		||||
  const nn_wctime_t tstamp = (sampleinfo->timestamp.v != NN_WCTIME_INVALID.v) ? sampleinfo->timestamp : ((nn_wctime_t) {0});
 | 
			
		||||
  struct ddsi_writer_info wrinfo;
 | 
			
		||||
  ddsi_make_writer_info (&wrinfo, &pwr->e, pwr->c.xqos);
 | 
			
		||||
 | 
			
		||||
  /* Generate the DDS_SampleInfo (which is faked to some extent
 | 
			
		||||
     because we don't actually have a data reader) */
 | 
			
		||||
  struct ddsi_tkmap_instance *tk;
 | 
			
		||||
  if ((tk = ddsi_tkmap_lookup_instance_ref (pwr->e.gv->m_tkmap, payload)) != NULL)
 | 
			
		||||
  if (rdguid == NULL)
 | 
			
		||||
  {
 | 
			
		||||
    struct proxy_writer_info pwr_info;
 | 
			
		||||
    make_proxy_writer_info (&pwr_info, &pwr->e, pwr->c.xqos);
 | 
			
		||||
 | 
			
		||||
    if (rdguid == NULL)
 | 
			
		||||
    /* FIXME: Retry loop, for re-delivery of rejected reliable samples. Is a
 | 
			
		||||
       temporary hack till throttling back of writer is implemented (with late
 | 
			
		||||
       acknowledgement of sample and nack). */
 | 
			
		||||
  retry:
 | 
			
		||||
    ddsrt_mutex_lock (&pwr->rdary.rdary_lock);
 | 
			
		||||
    if (pwr->rdary.fastpath_ok)
 | 
			
		||||
    {
 | 
			
		||||
      ETRACE (pwr, " %"PRId64"=>EVERYONE\n", sampleinfo->seq);
 | 
			
		||||
 | 
			
		||||
      /* FIXME: pwr->rdary is an array of pointers to attached
 | 
			
		||||
       readers.  There's only one thread delivering data for the
 | 
			
		||||
       proxy writer (as long as there is only one receive thread),
 | 
			
		||||
       so could get away with not locking at all, and doing safe
 | 
			
		||||
       updates + GC of rdary instead.  */
 | 
			
		||||
 | 
			
		||||
      /* Retry loop, for re-delivery of rejected reliable samples. Is a
 | 
			
		||||
       temporary hack till throttling back of writer is implemented
 | 
			
		||||
       (with late acknowledgement of sample and nack). */
 | 
			
		||||
    retry:
 | 
			
		||||
 | 
			
		||||
      ddsrt_mutex_lock (&pwr->rdary.rdary_lock);
 | 
			
		||||
      if (pwr->rdary.fastpath_ok)
 | 
			
		||||
      struct reader ** const rdary = pwr->rdary.rdary;
 | 
			
		||||
      if (rdary[0])
 | 
			
		||||
      {
 | 
			
		||||
        struct reader ** const rdary = pwr->rdary.rdary;
 | 
			
		||||
        for (uint32_t i = 0; rdary[i]; i++)
 | 
			
		||||
        struct ddsi_serdata *payload;
 | 
			
		||||
        struct ddsi_tkmap_instance *tk;
 | 
			
		||||
        if ((payload = new_sample_from_data (&tk, gv, sampleinfo, data_smhdr_flags, &qos, fragchain, statusinfo, tstamp, rdary[0]->topic)) != NULL)
 | 
			
		||||
        {
 | 
			
		||||
          ETRACE (pwr, "reader "PGUIDFMT"\n", PGUID (rdary[i]->e.guid));
 | 
			
		||||
          if (!rhc_store (rdary[i]->rhc, &pwr_info, payload, tk))
 | 
			
		||||
          {
 | 
			
		||||
            if (pwr_locked) ddsrt_mutex_unlock (&pwr->e.lock);
 | 
			
		||||
            ddsrt_mutex_unlock (&pwr->rdary.rdary_lock);
 | 
			
		||||
            dds_sleepfor (DDS_MSECS (10));
 | 
			
		||||
            if (pwr_locked) ddsrt_mutex_lock (&pwr->e.lock);
 | 
			
		||||
            goto retry;
 | 
			
		||||
          }
 | 
			
		||||
          ETRACE (pwr, " => EVERYONE\n");
 | 
			
		||||
          uint32_t i = 0;
 | 
			
		||||
          do {
 | 
			
		||||
            if (!ddsi_rhc_store (rdary[i]->rhc, &wrinfo, payload, tk))
 | 
			
		||||
            {
 | 
			
		||||
              if (pwr_locked) ddsrt_mutex_unlock (&pwr->e.lock);
 | 
			
		||||
              ddsrt_mutex_unlock (&pwr->rdary.rdary_lock);
 | 
			
		||||
              /* It is painful to drop the sample, but there is no guarantee that the readers
 | 
			
		||||
                 will still be there after unlocking; indeed, it is even possible that the
 | 
			
		||||
                 topic definition got replaced in the meantime.  Fortunately, this is in
 | 
			
		||||
                 the midst of a FIXME for many other reasons. */
 | 
			
		||||
              free_sample_after_store (gv, payload, tk);
 | 
			
		||||
              dds_sleepfor (DDS_MSECS (10));
 | 
			
		||||
              if (pwr_locked) ddsrt_mutex_lock (&pwr->e.lock);
 | 
			
		||||
              goto retry;
 | 
			
		||||
            }
 | 
			
		||||
          } while (rdary[++i]);
 | 
			
		||||
          free_sample_after_store (gv, payload, tk);
 | 
			
		||||
        }
 | 
			
		||||
        ddsrt_mutex_unlock (&pwr->rdary.rdary_lock);
 | 
			
		||||
      }
 | 
			
		||||
      else
 | 
			
		||||
      {
 | 
			
		||||
        /* When deleting, pwr is no longer accessible via the hash
 | 
			
		||||
      ddsrt_mutex_unlock (&pwr->rdary.rdary_lock);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
      /* When deleting, pwr is no longer accessible via the hash
 | 
			
		||||
         tables, and consequently, a reader may be deleted without
 | 
			
		||||
         it being possible to remove it from rdary. The primary
 | 
			
		||||
         reason rdary exists is to avoid locking the proxy writer
 | 
			
		||||
| 
						 | 
				
			
			@ -1988,51 +2007,72 @@ static int deliver_user_data (const struct nn_rsample_info *sampleinfo, const st
 | 
			
		|||
         we fall back to using the GUIDs so that we can deliver all
 | 
			
		||||
         samples we received from it. As writer being deleted any
 | 
			
		||||
         reliable samples that are rejected are simply discarded. */
 | 
			
		||||
        ddsrt_avl_iter_t it;
 | 
			
		||||
        struct pwr_rd_match *m;
 | 
			
		||||
        ddsrt_mutex_unlock (&pwr->rdary.rdary_lock);
 | 
			
		||||
        if (!pwr_locked) ddsrt_mutex_lock (&pwr->e.lock);
 | 
			
		||||
        for (m = ddsrt_avl_iter_first (&pwr_readers_treedef, &pwr->readers, &it); m != NULL; m = ddsrt_avl_iter_next (&it))
 | 
			
		||||
      ddsrt_avl_iter_t it;
 | 
			
		||||
      struct reader *rd;
 | 
			
		||||
      ddsrt_mutex_unlock (&pwr->rdary.rdary_lock);
 | 
			
		||||
      if (!pwr_locked) ddsrt_mutex_lock (&pwr->e.lock);
 | 
			
		||||
      if ((rd = proxy_writer_first_in_sync_reader (pwr, &it)) != NULL)
 | 
			
		||||
      {
 | 
			
		||||
        struct ddsi_serdata *payload;
 | 
			
		||||
        struct ddsi_tkmap_instance *tk;
 | 
			
		||||
        if ((payload = new_sample_from_data (&tk, gv, sampleinfo, data_smhdr_flags, &qos, fragchain, statusinfo, tstamp, rd->topic)) != NULL)
 | 
			
		||||
        {
 | 
			
		||||
          struct reader *rd;
 | 
			
		||||
          if ((rd = ephash_lookup_reader_guid (pwr->e.gv->guid_hash, &m->rd_guid)) != NULL && m->in_sync == PRMSS_SYNC)
 | 
			
		||||
          ETRACE (pwr, " =>");
 | 
			
		||||
          do {
 | 
			
		||||
            ETRACE (pwr, " "PGUIDFMT, PGUID (rd->e.guid));
 | 
			
		||||
            (void) ddsi_rhc_store (rd->rhc, &wrinfo, payload, tk);
 | 
			
		||||
            rd = proxy_writer_next_in_sync_reader (pwr, &it);
 | 
			
		||||
          } while (rd != NULL);
 | 
			
		||||
          free_sample_after_store (gv, payload, tk);
 | 
			
		||||
          ETRACE (pwr, "\n");
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      if (!pwr_locked) ddsrt_mutex_unlock (&pwr->e.lock);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ddsrt_atomic_st32 (&pwr->next_deliv_seq_lowword, (uint32_t) (sampleinfo->seq + 1));
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
    struct reader *rd = ephash_lookup_reader_guid (gv->guid_hash, rdguid);
 | 
			
		||||
    if (rd != NULL)
 | 
			
		||||
    {
 | 
			
		||||
      struct ddsi_serdata *payload;
 | 
			
		||||
      struct ddsi_tkmap_instance *tk;
 | 
			
		||||
      if ((payload = new_sample_from_data (&tk, gv, sampleinfo, data_smhdr_flags, &qos, fragchain, statusinfo, tstamp, rd->topic)) != NULL)
 | 
			
		||||
      {
 | 
			
		||||
        ETRACE (pwr, " =>"PGUIDFMT"\n", PGUID (*rdguid));
 | 
			
		||||
        /* FIXME: why look up rd,pwr again? Their states remains valid while the thread stays
 | 
			
		||||
           "awake" (although a delete can be initiated), and blocking like this is a stopgap
 | 
			
		||||
           anyway -- quite possibly to abort once either is deleted */
 | 
			
		||||
        while (!ddsi_rhc_store (rd->rhc, &wrinfo, payload, tk))
 | 
			
		||||
        {
 | 
			
		||||
          if (pwr_locked) ddsrt_mutex_unlock (&pwr->e.lock);
 | 
			
		||||
          dds_sleepfor (DDS_MSECS (1));
 | 
			
		||||
          if (pwr_locked) ddsrt_mutex_lock (&pwr->e.lock);
 | 
			
		||||
          if (ephash_lookup_reader_guid (gv->guid_hash, rdguid) == NULL ||
 | 
			
		||||
              ephash_lookup_proxy_writer_guid (gv->guid_hash, &pwr->e.guid) == NULL)
 | 
			
		||||
          {
 | 
			
		||||
            ETRACE (pwr, "reader-via-guid "PGUIDFMT"\n", PGUID (rd->e.guid));
 | 
			
		||||
            (void) rhc_store (rd->rhc, &pwr_info, payload, tk);
 | 
			
		||||
            /* give up when reader or proxy writer no longer accessible */
 | 
			
		||||
            break;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        if (!pwr_locked) ddsrt_mutex_unlock (&pwr->e.lock);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      ddsrt_atomic_st32 (&pwr->next_deliv_seq_lowword, (uint32_t) (sampleinfo->seq + 1));
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
      struct reader *rd = ephash_lookup_reader_guid (pwr->e.gv->guid_hash, rdguid);
 | 
			
		||||
      ETRACE (pwr, " %"PRId64"=>"PGUIDFMT"%s\n", sampleinfo->seq, PGUID (*rdguid), rd ? "" : "?");
 | 
			
		||||
      while (rd && ! rhc_store (rd->rhc, &pwr_info, payload, tk) && ephash_lookup_proxy_writer_guid (pwr->e.gv->guid_hash, &pwr->e.guid))
 | 
			
		||||
      {
 | 
			
		||||
        if (pwr_locked) ddsrt_mutex_unlock (&pwr->e.lock);
 | 
			
		||||
        dds_sleepfor (DDS_MSECS (1));
 | 
			
		||||
        if (pwr_locked) ddsrt_mutex_lock (&pwr->e.lock);
 | 
			
		||||
        free_sample_after_store (gv, payload, tk);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    ddsi_tkmap_instance_unref (pwr->e.gv->m_tkmap, tk);
 | 
			
		||||
  }
 | 
			
		||||
  ddsi_serdata_unref (payload);
 | 
			
		||||
 no_payload:
 | 
			
		||||
  nn_plist_fini (&qos);
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int user_dqueue_handler (const struct nn_rsample_info *sampleinfo, const struct nn_rdata *fragchain, const nn_guid_t *rdguid, UNUSED_ARG (void *qarg))
 | 
			
		||||
int user_dqueue_handler (const struct nn_rsample_info *sampleinfo, const struct nn_rdata *fragchain, const ddsi_guid_t *rdguid, UNUSED_ARG (void *qarg))
 | 
			
		||||
{
 | 
			
		||||
  int res;
 | 
			
		||||
  res = deliver_user_data (sampleinfo, fragchain, rdguid, 0);
 | 
			
		||||
  return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void deliver_user_data_synchronously (struct nn_rsample_chain *sc, const nn_guid_t *rdguid)
 | 
			
		||||
static void deliver_user_data_synchronously (struct nn_rsample_chain *sc, const ddsi_guid_t *rdguid)
 | 
			
		||||
{
 | 
			
		||||
  while (sc->first)
 | 
			
		||||
  {
 | 
			
		||||
| 
						 | 
				
			
			@ -2073,7 +2113,7 @@ static void handle_regular (struct receiver_state *rst, nn_etime_t tnow, struct
 | 
			
		|||
{
 | 
			
		||||
  struct proxy_writer *pwr;
 | 
			
		||||
  struct nn_rsample *rsample;
 | 
			
		||||
  nn_guid_t dst;
 | 
			
		||||
  ddsi_guid_t dst;
 | 
			
		||||
 | 
			
		||||
  dst.prefix = rst->dst_guid_prefix;
 | 
			
		||||
  dst.entityid = msg->readerId;
 | 
			
		||||
| 
						 | 
				
			
			@ -2081,7 +2121,7 @@ static void handle_regular (struct receiver_state *rst, nn_etime_t tnow, struct
 | 
			
		|||
  pwr = sampleinfo->pwr;
 | 
			
		||||
  if (pwr == NULL)
 | 
			
		||||
  {
 | 
			
		||||
    nn_guid_t src;
 | 
			
		||||
    ddsi_guid_t src;
 | 
			
		||||
    src.prefix = rst->src_guid_prefix;
 | 
			
		||||
    src.entityid = msg->writerId;
 | 
			
		||||
    RSTTRACE (" "PGUIDFMT"? -> "PGUIDFMT, PGUID (src), PGUID (dst));
 | 
			
		||||
| 
						 | 
				
			
			@ -2293,7 +2333,7 @@ static void drop_oversize (struct receiver_state *rst, struct nn_rmsg *rmsg, con
 | 
			
		|||
       effect seems a reasonable approach. */
 | 
			
		||||
    int refc_adjust = 0;
 | 
			
		||||
    struct nn_rdata *gap = nn_rdata_newgap (rmsg);
 | 
			
		||||
    nn_guid_t dst;
 | 
			
		||||
    ddsi_guid_t dst;
 | 
			
		||||
    struct pwr_rd_match *wn;
 | 
			
		||||
    int gap_was_valuable;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2308,8 +2348,8 @@ static void drop_oversize (struct receiver_state *rst, struct nn_rmsg *rmsg, con
 | 
			
		|||
 | 
			
		||||
    if (gap_was_valuable)
 | 
			
		||||
    {
 | 
			
		||||
      const char *tname = pwr->c.topic ? pwr->c.topic->name : "(null)";
 | 
			
		||||
      const char *ttname = pwr->c.topic ? pwr->c.topic->type_name : "(null)";
 | 
			
		||||
      const char *tname = (pwr->c.xqos->present & QP_TOPIC_NAME) ? pwr->c.xqos->topic_name : "(null)";
 | 
			
		||||
      const char *ttname = (pwr->c.xqos->present & QP_TYPE_NAME) ? pwr->c.xqos->type_name : "(null)";
 | 
			
		||||
      DDS_CWARNING (&rst->gv->logconfig, "dropping oversize (%"PRIu32" > %"PRIu32") sample %"PRId64" from remote writer "PGUIDFMT" %s/%s\n",
 | 
			
		||||
                    sampleinfo->size, rst->gv->config.max_sample_size, sampleinfo->seq,
 | 
			
		||||
                    PGUIDPREFIX (rst->src_guid_prefix), msg->writerId.u,
 | 
			
		||||
| 
						 | 
				
			
			@ -2397,7 +2437,7 @@ static int handle_DataFrag (struct receiver_state *rst, nn_etime_t tnow, struct
 | 
			
		|||
      payload_offset = submsg_offset + (unsigned) size;
 | 
			
		||||
 | 
			
		||||
    begin = (msg->fragmentStartingNum - 1) * msg->fragmentSize;
 | 
			
		||||
    if (msg->fragmentSize * msg->fragmentsInSubmessage > ((unsigned char *) msg + size - datap)) {
 | 
			
		||||
    if ((uint32_t) msg->fragmentSize * msg->fragmentsInSubmessage > (uint32_t) ((unsigned char *) msg + size - datap)) {
 | 
			
		||||
      /* this happens for the last fragment (which usually is short) --
 | 
			
		||||
         and is included here merely as a sanity check, because that
 | 
			
		||||
         would mean the computed endp1'd be larger than the sample
 | 
			
		||||
| 
						 | 
				
			
			@ -2587,8 +2627,8 @@ static int handle_submsg_sequence
 | 
			
		|||
  const nn_locator_t *srcloc,
 | 
			
		||||
  nn_wctime_t tnowWC,
 | 
			
		||||
  nn_etime_t tnowE,
 | 
			
		||||
  const nn_guid_prefix_t * const src_prefix,
 | 
			
		||||
  const nn_guid_prefix_t * const dst_prefix,
 | 
			
		||||
  const ddsi_guid_prefix_t * const src_prefix,
 | 
			
		||||
  const ddsi_guid_prefix_t * const dst_prefix,
 | 
			
		||||
  unsigned char * const msg /* NOT const - we may byteswap it */,
 | 
			
		||||
  const size_t len,
 | 
			
		||||
  unsigned char * submsg /* aliases somewhere in msg */,
 | 
			
		||||
| 
						 | 
				
			
			@ -2897,7 +2937,7 @@ malformed_asleep:
 | 
			
		|||
  return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool do_packet (struct thread_state1 * const ts1, struct q_globals *gv, ddsi_tran_conn_t conn, const nn_guid_prefix_t *guidprefix, struct nn_rbufpool *rbpool)
 | 
			
		||||
static bool do_packet (struct thread_state1 * const ts1, struct q_globals *gv, ddsi_tran_conn_t conn, const ddsi_guid_prefix_t *guidprefix, struct nn_rbufpool *rbpool)
 | 
			
		||||
{
 | 
			
		||||
  /* UDP max packet size is 64kB */
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3017,7 +3057,7 @@ static bool do_packet (struct thread_state1 * const ts1, struct q_globals *gv, d
 | 
			
		|||
struct local_participant_desc
 | 
			
		||||
{
 | 
			
		||||
  ddsi_tran_conn_t m_conn;
 | 
			
		||||
  nn_guid_prefix_t guid_prefix;
 | 
			
		||||
  ddsi_guid_prefix_t guid_prefix;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int local_participant_cmp (const void *va, const void *vb)
 | 
			
		||||
| 
						 | 
				
			
			@ -3369,7 +3409,7 @@ uint32_t recv_thread (void *vrecv_thread_arg)
 | 
			
		|||
        ddsi_tran_conn_t conn;
 | 
			
		||||
        while ((idx = os_sockWaitsetNextEvent (ctx, &conn)) >= 0)
 | 
			
		||||
        {
 | 
			
		||||
          const nn_guid_prefix_t *guid_prefix;
 | 
			
		||||
          const ddsi_guid_prefix_t *guid_prefix;
 | 
			
		||||
          if (((unsigned)idx < num_fixed) || gv->config.many_sockets_mode != MSM_MANY_UNICAST)
 | 
			
		||||
            guid_prefix = NULL;
 | 
			
		||||
          else
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,28 +0,0 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
 | 
			
		||||
 *
 | 
			
		||||
 * This program and the accompanying materials are made available under the
 | 
			
		||||
 * terms of the Eclipse Public License v. 2.0 which is available at
 | 
			
		||||
 * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
 | 
			
		||||
 * v. 1.0 which is available at
 | 
			
		||||
 * http://www.eclipse.org/org/documents/edl-v10.php.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
#include "dds/ddsi/q_rhc.h"
 | 
			
		||||
#include "dds/ddsi/q_xqos.h"
 | 
			
		||||
#include "dds/ddsi/q_entity.h"
 | 
			
		||||
 | 
			
		||||
extern inline void rhc_free (struct rhc *rhc);
 | 
			
		||||
extern inline bool rhc_store (struct rhc * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info, struct ddsi_serdata * __restrict sample, struct ddsi_tkmap_instance * __restrict tk);
 | 
			
		||||
extern inline void rhc_unregister_wr (struct rhc * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info);
 | 
			
		||||
extern inline void rhc_relinquish_ownership (struct rhc * __restrict rhc, const uint64_t wr_iid);
 | 
			
		||||
extern inline void rhc_set_qos (struct rhc *rhc, const struct dds_qos *qos);
 | 
			
		||||
 | 
			
		||||
void make_proxy_writer_info(struct proxy_writer_info *pwr_info, const struct entity_common *e, const struct dds_qos *xqos)
 | 
			
		||||
{
 | 
			
		||||
  pwr_info->guid = e->guid;
 | 
			
		||||
  pwr_info->ownership_strength = xqos->ownership_strength.value;
 | 
			
		||||
  pwr_info->auto_dispose = xqos->writer_data_lifecycle.autodispose_unregistered_instances;
 | 
			
		||||
  pwr_info->iid = e->iid;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -618,12 +618,23 @@ static void os_sockWaitsetNewSet (os_sockWaitsetSet * set)
 | 
			
		|||
  set->n = 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void os_sockWaitsetFreeSet (os_sockWaitsetSet * set)
 | 
			
		||||
{
 | 
			
		||||
  ddsrt_free (set->fds);
 | 
			
		||||
  ddsrt_free (set->conns);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void os_sockWaitsetNewCtx (os_sockWaitsetCtx ctx)
 | 
			
		||||
{
 | 
			
		||||
  os_sockWaitsetNewSet (&ctx->set);
 | 
			
		||||
  FD_ZERO (&ctx->rdset);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void os_sockWaitsetFreeCtx (os_sockWaitsetCtx ctx)
 | 
			
		||||
{
 | 
			
		||||
  os_sockWaitsetFreeSet (&ctx->set);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
os_sockWaitset os_sockWaitsetNew (void)
 | 
			
		||||
{
 | 
			
		||||
  int result;
 | 
			
		||||
| 
						 | 
				
			
			@ -642,40 +653,16 @@ os_sockWaitset os_sockWaitsetNew (void)
 | 
			
		|||
  ws->pipe[0] = -1;
 | 
			
		||||
  ws->pipe[1] = -1;
 | 
			
		||||
  result = 0;
 | 
			
		||||
#elif defined(__VXWORKS__)
 | 
			
		||||
  int make_pipe (int pfd[2])
 | 
			
		||||
  {
 | 
			
		||||
    char pipename[OSPL_PIPENAMESIZE];
 | 
			
		||||
    int pipecount=0;
 | 
			
		||||
    do
 | 
			
		||||
    {
 | 
			
		||||
      snprintf ((char*)&pipename, sizeof(pipename), "/pipe/ospl%d", pipecount++ );
 | 
			
		||||
    }
 | 
			
		||||
    while ((result = pipeDevCreate ((char*) &pipename, 1, 1)) == -1 && os_getErrno() == EINVAL);
 | 
			
		||||
    if (result != -1)
 | 
			
		||||
    {
 | 
			
		||||
      result = open ((char*) &pipename, O_RDWR, 0644);
 | 
			
		||||
      if (result != -1)
 | 
			
		||||
      {
 | 
			
		||||
        ws->pipe[0] = result;
 | 
			
		||||
        result = open ((char*) &pipename, O_RDWR, 0644);
 | 
			
		||||
        if (result != -1)
 | 
			
		||||
        {
 | 
			
		||||
          ws->pipe[1] = result;
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
          close (ws->pipe[0]);
 | 
			
		||||
          pipeDevDelete (pipename, 0);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
#else
 | 
			
		||||
  result = make_pipe (ws->pipe);
 | 
			
		||||
#endif
 | 
			
		||||
  assert (result != -1);
 | 
			
		||||
  (void) result;
 | 
			
		||||
  if (result == -1)
 | 
			
		||||
  {
 | 
			
		||||
    os_sockWaitsetFreeCtx (&ws->ctx);
 | 
			
		||||
    os_sockWaitsetFreeSet (&ws->set);
 | 
			
		||||
    ddsrt_free (ws);
 | 
			
		||||
    return NULL;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
#if !defined(LWIP_SOCKET)
 | 
			
		||||
  ws->set.fds[0] = ws->pipe[0];
 | 
			
		||||
| 
						 | 
				
			
			@ -685,8 +672,8 @@ os_sockWaitset os_sockWaitsetNew (void)
 | 
			
		|||
  ws->set.conns[0] = NULL;
 | 
			
		||||
 | 
			
		||||
#if !defined(__VXWORKS__) && !defined(_WIN32) && !defined(LWIP_SOCKET)
 | 
			
		||||
  fcntl (ws->pipe[0], F_SETFD, fcntl (ws->pipe[0], F_GETFD) | FD_CLOEXEC);
 | 
			
		||||
  fcntl (ws->pipe[1], F_SETFD, fcntl (ws->pipe[1], F_GETFD) | FD_CLOEXEC);
 | 
			
		||||
  (void) fcntl (ws->pipe[0], F_SETFD, fcntl (ws->pipe[0], F_GETFD) | FD_CLOEXEC);
 | 
			
		||||
  (void) fcntl (ws->pipe[1], F_SETFD, fcntl (ws->pipe[1], F_GETFD) | FD_CLOEXEC);
 | 
			
		||||
#endif
 | 
			
		||||
#if !defined(LWIP_SOCKET)
 | 
			
		||||
  FD_SET (ws->set.fds[0], &ws->ctx.rdset);
 | 
			
		||||
| 
						 | 
				
			
			@ -707,17 +694,6 @@ static void os_sockWaitsetGrow (os_sockWaitsetSet * set)
 | 
			
		|||
  set->fds = ddsrt_realloc (set->fds, set->sz * sizeof (*set->fds));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void os_sockWaitsetFreeSet (os_sockWaitsetSet * set)
 | 
			
		||||
{
 | 
			
		||||
  ddsrt_free (set->fds);
 | 
			
		||||
  ddsrt_free (set->conns);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void os_sockWaitsetFreeCtx (os_sockWaitsetCtx ctx)
 | 
			
		||||
{
 | 
			
		||||
  os_sockWaitsetFreeSet (&ctx->set);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void os_sockWaitsetFree (os_sockWaitset ws)
 | 
			
		||||
{
 | 
			
		||||
#if defined(__VXWORKS__) && defined(__RTP__)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,8 +28,6 @@
 | 
			
		|||
#include "dds/ddsi/q_globals.h"
 | 
			
		||||
#include "dds/ddsi/sysdeps.h"
 | 
			
		||||
 | 
			
		||||
static char main_thread_name[] = "main";
 | 
			
		||||
 | 
			
		||||
struct thread_states thread_states;
 | 
			
		||||
ddsrt_thread_local struct thread_state1 *tsd_thread_state;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -47,6 +45,7 @@ extern inline void thread_state_awake_fixed_domain (struct thread_state1 *ts1);
 | 
			
		|||
extern inline void thread_state_awake_to_awake_no_nest (struct thread_state1 *ts1);
 | 
			
		||||
 | 
			
		||||
static struct thread_state1 *init_thread_state (const char *tname, const struct q_globals *gv, enum thread_state state);
 | 
			
		||||
static void reap_thread_state (struct thread_state1 *ts1);
 | 
			
		||||
 | 
			
		||||
static void *ddsrt_malloc_aligned_cacheline (size_t size)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -74,45 +73,74 @@ static void ddsrt_free_aligned (void *ptr)
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void thread_states_init_static (void)
 | 
			
		||||
{
 | 
			
		||||
  static struct thread_state1 ts = {
 | 
			
		||||
    .state = THREAD_STATE_ALIVE, .vtime = DDSRT_ATOMIC_UINT32_INIT (0), .name = "(anon)"
 | 
			
		||||
  };
 | 
			
		||||
  tsd_thread_state = &ts;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void thread_states_init (unsigned maxthreads)
 | 
			
		||||
{
 | 
			
		||||
  ddsrt_mutex_init (&thread_states.lock);
 | 
			
		||||
  thread_states.nthreads = maxthreads;
 | 
			
		||||
  thread_states.ts =
 | 
			
		||||
    ddsrt_malloc_aligned_cacheline (maxthreads * sizeof (*thread_states.ts));
 | 
			
		||||
  memset (thread_states.ts, 0, maxthreads * sizeof (*thread_states.ts));
 | 
			
		||||
  /* The compiler doesn't realize that ts is large enough. */
 | 
			
		||||
  DDSRT_WARNING_MSVC_OFF(6386);
 | 
			
		||||
  for (uint32_t i = 0; i < thread_states.nthreads; i++)
 | 
			
		||||
  /* Called with ddsrt's singleton mutex held (see dds_init/fini).  Application threads
 | 
			
		||||
     remaining alive can result in thread_states remaining alive, and as those thread
 | 
			
		||||
     cache the address, we must then re-use the old array. */
 | 
			
		||||
  if (thread_states.ts == NULL)
 | 
			
		||||
  {
 | 
			
		||||
    thread_states.ts[i].state = THREAD_STATE_ZERO;
 | 
			
		||||
    ddsrt_atomic_st32 (&thread_states.ts[i].vtime, 0);
 | 
			
		||||
    memset (thread_states.ts[i].name, 0, sizeof (thread_states.ts[i].name));
 | 
			
		||||
    ddsrt_mutex_init (&thread_states.lock);
 | 
			
		||||
    thread_states.nthreads = maxthreads;
 | 
			
		||||
    thread_states.ts = ddsrt_malloc_aligned_cacheline (maxthreads * sizeof (*thread_states.ts));
 | 
			
		||||
    memset (thread_states.ts, 0, maxthreads * sizeof (*thread_states.ts));
 | 
			
		||||
    /* The compiler doesn't realize that ts is large enough. */
 | 
			
		||||
    DDSRT_WARNING_MSVC_OFF(6386);
 | 
			
		||||
    for (uint32_t i = 0; i < thread_states.nthreads; i++)
 | 
			
		||||
    {
 | 
			
		||||
      thread_states.ts[i].state = THREAD_STATE_ZERO;
 | 
			
		||||
      ddsrt_atomic_st32 (&thread_states.ts[i].vtime, 0);
 | 
			
		||||
      memset (thread_states.ts[i].name, 0, sizeof (thread_states.ts[i].name));
 | 
			
		||||
    }
 | 
			
		||||
    DDSRT_WARNING_MSVC_ON(6386);
 | 
			
		||||
  }
 | 
			
		||||
  DDSRT_WARNING_MSVC_ON(6386);
 | 
			
		||||
 | 
			
		||||
  /* This thread should be at the same address as before, or never have had a slot
 | 
			
		||||
     in the past.  Also, allocate a slot for this thread if it didn't have one yet
 | 
			
		||||
     (not strictly required, but it'll get one eventually anyway, and this makes
 | 
			
		||||
     it rather more clear). */
 | 
			
		||||
#ifndef NDEBUG
 | 
			
		||||
  struct thread_state1 * const ts0 = tsd_thread_state;
 | 
			
		||||
#endif
 | 
			
		||||
  struct thread_state1 * const ts1 = lookup_thread_state_real ();
 | 
			
		||||
  assert (ts0 == NULL || ts0 == ts1);
 | 
			
		||||
  (void) ts1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void thread_states_fini (void)
 | 
			
		||||
bool thread_states_fini (void)
 | 
			
		||||
{
 | 
			
		||||
  for (uint32_t i = 0; i < thread_states.nthreads; i++)
 | 
			
		||||
    assert (thread_states.ts[i].state != THREAD_STATE_ALIVE);
 | 
			
		||||
  ddsrt_mutex_destroy (&thread_states.lock);
 | 
			
		||||
  ddsrt_free_aligned (thread_states.ts);
 | 
			
		||||
  /* Calling thread is the one shutting everything down, so it certainly won't (well, shouldn't)
 | 
			
		||||
     need its slot anymore.  Clean it up so that if all other threads happen to have been stopped
 | 
			
		||||
     already, we can release all resources. */
 | 
			
		||||
  struct thread_state1 *ts1 = lookup_thread_state ();
 | 
			
		||||
  assert (vtime_asleep_p (ddsrt_atomic_ld32 (&ts1->vtime)));
 | 
			
		||||
  reap_thread_state (ts1);
 | 
			
		||||
  tsd_thread_state = NULL;
 | 
			
		||||
 | 
			
		||||
  /* All spawned threads are gone, but the main thread is still alive,
 | 
			
		||||
     downgraded to an ordinary thread (we're on it right now). We
 | 
			
		||||
     don't want to lose the ability to log messages, so set ts to a
 | 
			
		||||
     NULL pointer and rely on lookup_thread_state()'s checks
 | 
			
		||||
     thread_states.ts. */
 | 
			
		||||
  thread_states.ts = NULL;
 | 
			
		||||
  /* Some applications threads that, at some point, required a thread state, may still be around.
 | 
			
		||||
     Of those, the cleanup routine is invoked when the thread terminates.  This should be rewritten
 | 
			
		||||
     to not rely on this global thing and with each thread owning its own bit state, e.g., linked
 | 
			
		||||
     together in a list to give the GC access to it.  Until then, we can't release these resources
 | 
			
		||||
     if there are still users. */
 | 
			
		||||
  uint32_t others = 0;
 | 
			
		||||
  ddsrt_mutex_lock (&thread_states.lock);
 | 
			
		||||
  for (uint32_t i = 0; i < thread_states.nthreads; i++)
 | 
			
		||||
  {
 | 
			
		||||
    assert (thread_states.ts[i].state != THREAD_STATE_ALIVE);
 | 
			
		||||
    others += (thread_states.ts[i].state == THREAD_STATE_LAZILY_CREATED);
 | 
			
		||||
  }
 | 
			
		||||
  ddsrt_mutex_unlock (&thread_states.lock);
 | 
			
		||||
  if (others == 0)
 | 
			
		||||
  {
 | 
			
		||||
    ddsrt_mutex_destroy (&thread_states.lock);
 | 
			
		||||
    ddsrt_free_aligned (thread_states.ts);
 | 
			
		||||
    thread_states.ts = NULL;
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ddsrt_attribute_no_sanitize (("thread"))
 | 
			
		||||
| 
						 | 
				
			
			@ -121,7 +149,7 @@ static struct thread_state1 *find_thread_state (ddsrt_thread_t tid)
 | 
			
		|||
  if (thread_states.ts) {
 | 
			
		||||
    for (uint32_t i = 0; i < thread_states.nthreads; i++)
 | 
			
		||||
    {
 | 
			
		||||
      if (ddsrt_thread_equal (thread_states.ts[i].tid, tid))
 | 
			
		||||
      if (ddsrt_thread_equal (thread_states.ts[i].tid, tid) && thread_states.ts[i].state != THREAD_STATE_ZERO)
 | 
			
		||||
        return &thread_states.ts[i];
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -203,26 +231,6 @@ static int find_free_slot (const char *name)
 | 
			
		|||
  return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void upgrade_main_thread (void)
 | 
			
		||||
{
 | 
			
		||||
  int cand;
 | 
			
		||||
  struct thread_state1 *ts1;
 | 
			
		||||
  ddsrt_mutex_lock (&thread_states.lock);
 | 
			
		||||
  if ((cand = find_free_slot ("name")) < 0)
 | 
			
		||||
    abort ();
 | 
			
		||||
  ts1 = &thread_states.ts[cand];
 | 
			
		||||
  if (ts1->state == THREAD_STATE_ZERO)
 | 
			
		||||
    assert (vtime_asleep_p (ddsrt_atomic_ld32 (&ts1->vtime)));
 | 
			
		||||
  ts1->state = THREAD_STATE_LAZILY_CREATED;
 | 
			
		||||
  ts1->tid = ddsrt_thread_self ();
 | 
			
		||||
  DDSRT_WARNING_MSVC_OFF(4996);
 | 
			
		||||
  strncpy (ts1->name, main_thread_name, sizeof (ts1->name));
 | 
			
		||||
  DDSRT_WARNING_MSVC_ON(4996);
 | 
			
		||||
  ts1->name[sizeof (ts1->name) - 1] = 0;
 | 
			
		||||
  ddsrt_mutex_unlock (&thread_states.lock);
 | 
			
		||||
  tsd_thread_state = ts1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const struct config_thread_properties_listelem *lookup_thread_properties (const struct config *config, const char *name)
 | 
			
		||||
{
 | 
			
		||||
  const struct config_thread_properties_listelem *e;
 | 
			
		||||
| 
						 | 
				
			
			@ -332,15 +340,6 @@ void reset_thread_state (struct thread_state1 *ts1)
 | 
			
		|||
    reap_thread_state (ts1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void downgrade_main_thread (void)
 | 
			
		||||
{
 | 
			
		||||
  struct thread_state1 *ts1 = lookup_thread_state ();
 | 
			
		||||
  assert (vtime_asleep_p (ddsrt_atomic_ld32 (&ts1->vtime)));
 | 
			
		||||
  /* no need to sync with service lease: already stopped */
 | 
			
		||||
  reap_thread_state (ts1);
 | 
			
		||||
  thread_states_init_static ();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void log_stack_traces (const struct ddsrt_log_cfg *logcfg, const struct q_globals *gv)
 | 
			
		||||
{
 | 
			
		||||
  for (uint32_t i = 0; i < thread_states.nthreads; i++)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -134,7 +134,7 @@ struct nn_xmsg *writer_hbcontrol_create_heartbeat (struct writer *wr, const stru
 | 
			
		|||
{
 | 
			
		||||
  struct q_globals const * const gv = wr->e.gv;
 | 
			
		||||
  struct nn_xmsg *msg;
 | 
			
		||||
  const nn_guid_t *prd_guid;
 | 
			
		||||
  const ddsi_guid_t *prd_guid;
 | 
			
		||||
 | 
			
		||||
  ASSERT_MUTEX_HELD (&wr->e.lock);
 | 
			
		||||
  assert (wr->reliable);
 | 
			
		||||
| 
						 | 
				
			
			@ -163,7 +163,7 @@ struct nn_xmsg *writer_hbcontrol_create_heartbeat (struct writer *wr, const stru
 | 
			
		|||
  }
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
    const int n_unacked = wr->num_reliable_readers - root_rdmatch (wr)->num_reliable_readers_where_seq_equals_max;
 | 
			
		||||
    const int32_t n_unacked = wr->num_reliable_readers - root_rdmatch (wr)->num_reliable_readers_where_seq_equals_max;
 | 
			
		||||
    assert (n_unacked >= 0);
 | 
			
		||||
    if (n_unacked == 0)
 | 
			
		||||
      prd_guid = NULL;
 | 
			
		||||
| 
						 | 
				
			
			@ -182,7 +182,7 @@ struct nn_xmsg *writer_hbcontrol_create_heartbeat (struct writer *wr, const stru
 | 
			
		|||
    ETRACE (wr, "multicasting ");
 | 
			
		||||
  else
 | 
			
		||||
    ETRACE (wr, "unicasting to prd "PGUIDFMT" ", PGUID (*prd_guid));
 | 
			
		||||
  ETRACE (wr, "(rel-prd %d seq-eq-max %d seq %"PRId64" maxseq %"PRId64")\n",
 | 
			
		||||
  ETRACE (wr, "(rel-prd %"PRId32" seq-eq-max %"PRId32" seq %"PRId64" maxseq %"PRId64")\n",
 | 
			
		||||
          wr->num_reliable_readers,
 | 
			
		||||
          ddsrt_avl_is_empty (&wr->readers) ? -1 : root_rdmatch (wr)->num_reliable_readers_where_seq_equals_max,
 | 
			
		||||
          wr->seq,
 | 
			
		||||
| 
						 | 
				
			
			@ -313,7 +313,7 @@ struct nn_xmsg *writer_hbcontrol_piggyback (struct writer *wr, const struct whc_
 | 
			
		|||
  return msg;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void add_Heartbeat (struct nn_xmsg *msg, struct writer *wr, const struct whc_state *whcst, int hbansreq, nn_entityid_t dst, int issync)
 | 
			
		||||
void add_Heartbeat (struct nn_xmsg *msg, struct writer *wr, const struct whc_state *whcst, int hbansreq, ddsi_entityid_t dst, int issync)
 | 
			
		||||
{
 | 
			
		||||
  struct q_globals const * const gv = wr->e.gv;
 | 
			
		||||
  struct nn_xmsg_marker sm_marker;
 | 
			
		||||
| 
						 | 
				
			
			@ -859,6 +859,8 @@ static int insert_sample_in_whc (struct writer *wr, seqno_t seq, struct nn_plist
 | 
			
		|||
    const char *ttname = wr->topic ? wr->topic->type_name : "(null)";
 | 
			
		||||
    ppbuf[0] = '\0';
 | 
			
		||||
    tmp = sizeof (ppbuf) - 1;
 | 
			
		||||
    if (wr->e.gv->logconfig.c.mask & DDS_LC_CONTENT)
 | 
			
		||||
      ddsi_serdata_print (serdata, ppbuf, sizeof (ppbuf));
 | 
			
		||||
    ETRACE (wr, "write_sample "PGUIDFMT" #%"PRId64, PGUID (wr->e.guid), seq);
 | 
			
		||||
    if (plist != 0 && (plist->present & PP_COHERENT_SET))
 | 
			
		||||
      ETRACE (wr, " C#%"PRId64"", fromSN (plist->coherent_set_seqno));
 | 
			
		||||
| 
						 | 
				
			
			@ -898,7 +900,6 @@ static int writer_may_continue (const struct writer *wr, const struct whc_state
 | 
			
		|||
  return (whcst->unacked_bytes <= wr->whc_low && !wr->retransmitting) || (wr->state != WRST_OPERATIONAL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static dds_return_t throttle_writer (struct thread_state1 * const ts1, struct nn_xpack *xp, struct writer *wr)
 | 
			
		||||
{
 | 
			
		||||
  /* Sleep (cond_wait) without updating the thread's vtime: the
 | 
			
		||||
| 
						 | 
				
			
			@ -1082,6 +1083,13 @@ static int write_sample_eot (struct thread_state1 * const ts1, struct nn_xpack *
 | 
			
		|||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (wr->state != WRST_OPERATIONAL)
 | 
			
		||||
  {
 | 
			
		||||
    r = DDS_RETCODE_PRECONDITION_NOT_MET;
 | 
			
		||||
    ddsrt_mutex_unlock (&wr->e.lock);
 | 
			
		||||
    goto drop;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /* Always use the current monotonic time */
 | 
			
		||||
  tnow = now_mt ();
 | 
			
		||||
  serdata->twrite = tnow;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -68,26 +68,26 @@ struct xevent
 | 
			
		|||
  enum xeventkind kind;
 | 
			
		||||
  union {
 | 
			
		||||
    struct {
 | 
			
		||||
      nn_guid_t wr_guid;
 | 
			
		||||
      ddsi_guid_t wr_guid;
 | 
			
		||||
    } heartbeat;
 | 
			
		||||
    struct {
 | 
			
		||||
      nn_guid_t pwr_guid;
 | 
			
		||||
      nn_guid_t rd_guid;
 | 
			
		||||
      ddsi_guid_t pwr_guid;
 | 
			
		||||
      ddsi_guid_t rd_guid;
 | 
			
		||||
    } acknack;
 | 
			
		||||
    struct {
 | 
			
		||||
      nn_guid_t pp_guid;
 | 
			
		||||
      nn_guid_prefix_t dest_proxypp_guid_prefix; /* only if "directed" */
 | 
			
		||||
      ddsi_guid_t pp_guid;
 | 
			
		||||
      ddsi_guid_prefix_t dest_proxypp_guid_prefix; /* only if "directed" */
 | 
			
		||||
      int directed; /* if 0, undirected; if > 0, number of directed ones to send in reasonably short succession */
 | 
			
		||||
    } spdp;
 | 
			
		||||
    struct {
 | 
			
		||||
      nn_guid_t pp_guid;
 | 
			
		||||
      ddsi_guid_t pp_guid;
 | 
			
		||||
    } pmd_update;
 | 
			
		||||
#if 0
 | 
			
		||||
    struct {
 | 
			
		||||
    } info;
 | 
			
		||||
#endif
 | 
			
		||||
    struct {
 | 
			
		||||
      nn_guid_t guid;
 | 
			
		||||
      ddsi_guid_t guid;
 | 
			
		||||
    } delete_writer;
 | 
			
		||||
    struct {
 | 
			
		||||
      void (*cb) (struct xevent *ev, void *arg, nn_mtime_t tnow);
 | 
			
		||||
| 
						 | 
				
			
			@ -937,7 +937,7 @@ static void handle_xevk_acknack (UNUSED_ARG (struct nn_xpack *xp), struct xevent
 | 
			
		|||
  resched_xevent_if_earlier (ev, add_duration_to_mtime (tnow, 100 * T_MILLISECOND));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool resend_spdp_sample_by_guid_key (struct writer *wr, const nn_guid_t *guid, struct proxy_reader *prd)
 | 
			
		||||
static bool resend_spdp_sample_by_guid_key (struct writer *wr, const ddsi_guid_t *guid, struct proxy_reader *prd)
 | 
			
		||||
{
 | 
			
		||||
  /* Look up data in (transient-local) WHC by key value -- FIXME: clearly
 | 
			
		||||
   a slightly more efficient and elegant way of looking up the key value
 | 
			
		||||
| 
						 | 
				
			
			@ -1009,7 +1009,7 @@ static void handle_xevk_spdp (UNUSED_ARG (struct nn_xpack *xp), struct xevent *e
 | 
			
		|||
  }
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
    nn_guid_t guid;
 | 
			
		||||
    ddsi_guid_t guid;
 | 
			
		||||
    guid.prefix = ev->u.spdp.dest_proxypp_guid_prefix;
 | 
			
		||||
    guid.entityid.u = NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_READER;
 | 
			
		||||
    prd = ephash_lookup_proxy_reader_guid (gv->guid_hash, &guid);
 | 
			
		||||
| 
						 | 
				
			
			@ -1387,7 +1387,7 @@ void qxev_msg (struct xeventq *evq, struct nn_xmsg *msg)
 | 
			
		|||
  ddsrt_mutex_unlock (&evq->lock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void qxev_prd_entityid (struct proxy_reader *prd, nn_guid_prefix_t *id)
 | 
			
		||||
void qxev_prd_entityid (struct proxy_reader *prd, ddsi_guid_prefix_t *id)
 | 
			
		||||
{
 | 
			
		||||
  struct q_globals * const gv = prd->e.gv;
 | 
			
		||||
  struct nn_xmsg *msg;
 | 
			
		||||
| 
						 | 
				
			
			@ -1415,7 +1415,7 @@ void qxev_prd_entityid (struct proxy_reader *prd, nn_guid_prefix_t *id)
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void qxev_pwr_entityid (struct proxy_writer *pwr, nn_guid_prefix_t *id)
 | 
			
		||||
void qxev_pwr_entityid (struct proxy_writer *pwr, ddsi_guid_prefix_t *id)
 | 
			
		||||
{
 | 
			
		||||
  struct q_globals * const gv = pwr->e.gv;
 | 
			
		||||
  struct nn_xmsg *msg;
 | 
			
		||||
| 
						 | 
				
			
			@ -1488,7 +1488,7 @@ int qxev_msg_rexmit_wrlock_held (struct xeventq *evq, struct nn_xmsg *msg, int f
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct xevent *qxev_heartbeat (struct xeventq *evq, nn_mtime_t tsched, const nn_guid_t *wr_guid)
 | 
			
		||||
struct xevent *qxev_heartbeat (struct xeventq *evq, nn_mtime_t tsched, const ddsi_guid_t *wr_guid)
 | 
			
		||||
{
 | 
			
		||||
  /* Event _must_ be deleted before enough of the writer is freed to
 | 
			
		||||
     cause trouble.  Currently used exclusively for
 | 
			
		||||
| 
						 | 
				
			
			@ -1503,7 +1503,7 @@ struct xevent *qxev_heartbeat (struct xeventq *evq, nn_mtime_t tsched, const nn_
 | 
			
		|||
  return ev;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct xevent *qxev_acknack (struct xeventq *evq, nn_mtime_t tsched, const nn_guid_t *pwr_guid, const nn_guid_t *rd_guid)
 | 
			
		||||
struct xevent *qxev_acknack (struct xeventq *evq, nn_mtime_t tsched, const ddsi_guid_t *pwr_guid, const ddsi_guid_t *rd_guid)
 | 
			
		||||
{
 | 
			
		||||
  struct xevent *ev;
 | 
			
		||||
  assert(evq);
 | 
			
		||||
| 
						 | 
				
			
			@ -1516,7 +1516,7 @@ struct xevent *qxev_acknack (struct xeventq *evq, nn_mtime_t tsched, const nn_gu
 | 
			
		|||
  return ev;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct xevent *qxev_spdp (struct xeventq *evq, nn_mtime_t tsched, const nn_guid_t *pp_guid, const nn_guid_t *dest_proxypp_guid)
 | 
			
		||||
struct xevent *qxev_spdp (struct xeventq *evq, nn_mtime_t tsched, const ddsi_guid_t *pp_guid, const ddsi_guid_t *dest_proxypp_guid)
 | 
			
		||||
{
 | 
			
		||||
  struct xevent *ev;
 | 
			
		||||
  ddsrt_mutex_lock (&evq->lock);
 | 
			
		||||
| 
						 | 
				
			
			@ -1534,7 +1534,7 @@ struct xevent *qxev_spdp (struct xeventq *evq, nn_mtime_t tsched, const nn_guid_
 | 
			
		|||
  return ev;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct xevent *qxev_pmd_update (struct xeventq *evq, nn_mtime_t tsched, const nn_guid_t *pp_guid)
 | 
			
		||||
struct xevent *qxev_pmd_update (struct xeventq *evq, nn_mtime_t tsched, const ddsi_guid_t *pp_guid)
 | 
			
		||||
{
 | 
			
		||||
  struct xevent *ev;
 | 
			
		||||
  ddsrt_mutex_lock (&evq->lock);
 | 
			
		||||
| 
						 | 
				
			
			@ -1545,7 +1545,7 @@ struct xevent *qxev_pmd_update (struct xeventq *evq, nn_mtime_t tsched, const nn
 | 
			
		|||
  return ev;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct xevent *qxev_delete_writer (struct xeventq *evq, nn_mtime_t tsched, const nn_guid_t *guid)
 | 
			
		||||
struct xevent *qxev_delete_writer (struct xeventq *evq, nn_mtime_t tsched, const ddsi_guid_t *guid)
 | 
			
		||||
{
 | 
			
		||||
  struct xevent *ev;
 | 
			
		||||
  ddsrt_mutex_lock (&evq->lock);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -83,7 +83,7 @@ struct nn_xmsg {
 | 
			
		|||
  union {
 | 
			
		||||
    char control;
 | 
			
		||||
    struct {
 | 
			
		||||
      nn_guid_t wrguid;
 | 
			
		||||
      ddsi_guid_t wrguid;
 | 
			
		||||
      seqno_t wrseq;
 | 
			
		||||
      nn_fragment_number_t wrfragid;
 | 
			
		||||
      /* readerId encodes offset to destination readerId or 0 -- used
 | 
			
		||||
| 
						 | 
				
			
			@ -191,7 +191,7 @@ struct nn_xpack
 | 
			
		|||
  bool async_mode;
 | 
			
		||||
  Header_t hdr;
 | 
			
		||||
  MsgLen_t msg_len;
 | 
			
		||||
  nn_guid_prefix_t *last_src;
 | 
			
		||||
  ddsi_guid_prefix_t *last_src;
 | 
			
		||||
  InfoDST_t *last_dst;
 | 
			
		||||
  int64_t maxdelay;
 | 
			
		||||
  unsigned packetid;
 | 
			
		||||
| 
						 | 
				
			
			@ -329,7 +329,7 @@ static struct nn_xmsg *nn_xmsg_allocnew (struct nn_xmsgpool *pool, size_t expect
 | 
			
		|||
  return m;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct nn_xmsg *nn_xmsg_new (struct nn_xmsgpool *pool, const nn_guid_prefix_t *src_guid_prefix, size_t expected_size, enum nn_xmsg_kind kind)
 | 
			
		||||
struct nn_xmsg *nn_xmsg_new (struct nn_xmsgpool *pool, const ddsi_guid_prefix_t *src_guid_prefix, size_t expected_size, enum nn_xmsg_kind kind)
 | 
			
		||||
{
 | 
			
		||||
  struct nn_xmsg *m;
 | 
			
		||||
  if ((m = nn_freelist_pop (&pool->freelist)) != NULL)
 | 
			
		||||
| 
						 | 
				
			
			@ -460,7 +460,7 @@ enum nn_xmsg_kind nn_xmsg_kind (const struct nn_xmsg *m)
 | 
			
		|||
  return m->kind;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nn_xmsg_guid_seq_fragid (const struct nn_xmsg *m, nn_guid_t *wrguid, seqno_t *wrseq, nn_fragment_number_t *wrfragid)
 | 
			
		||||
void nn_xmsg_guid_seq_fragid (const struct nn_xmsg *m, ddsi_guid_t *wrguid, seqno_t *wrseq, nn_fragment_number_t *wrfragid)
 | 
			
		||||
{
 | 
			
		||||
  assert (m->kind != NN_XMSG_KIND_CONTROL);
 | 
			
		||||
  *wrguid = m->kindspecific.data.wrguid;
 | 
			
		||||
| 
						 | 
				
			
			@ -577,7 +577,7 @@ void nn_xmsg_serdata (struct nn_xmsg *m, struct ddsi_serdata *serdata, size_t of
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nn_xmsg_setdst1 (struct nn_xmsg *m, const nn_guid_prefix_t *gp, const nn_locator_t *loc)
 | 
			
		||||
void nn_xmsg_setdst1 (struct nn_xmsg *m, const ddsi_guid_prefix_t *gp, const nn_locator_t *loc)
 | 
			
		||||
{
 | 
			
		||||
  assert (m->dstmode == NN_XMSG_DST_UNSET);
 | 
			
		||||
  m->dstmode = NN_XMSG_DST_ONE;
 | 
			
		||||
| 
						 | 
				
			
			@ -620,7 +620,7 @@ void nn_xmsg_setdstN (struct nn_xmsg *m, struct addrset *as, struct addrset *as_
 | 
			
		|||
  m->dstaddr.all.as_group = ref_addrset (as_group);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nn_xmsg_set_data_readerId (struct nn_xmsg *m, nn_entityid_t *readerId)
 | 
			
		||||
void nn_xmsg_set_data_readerId (struct nn_xmsg *m, ddsi_entityid_t *readerId)
 | 
			
		||||
{
 | 
			
		||||
  assert (m->kind == NN_XMSG_KIND_DATA_REXMIT);
 | 
			
		||||
  assert (m->kindspecific.data.readerId_off == 0);
 | 
			
		||||
| 
						 | 
				
			
			@ -633,21 +633,21 @@ static void clear_readerId (struct nn_xmsg *m)
 | 
			
		|||
{
 | 
			
		||||
  assert (m->kind == NN_XMSG_KIND_DATA_REXMIT);
 | 
			
		||||
  assert (m->kindspecific.data.readerId_off != 0);
 | 
			
		||||
  *((nn_entityid_t *) (m->data->payload + m->kindspecific.data.readerId_off)) =
 | 
			
		||||
  *((ddsi_entityid_t *) (m->data->payload + m->kindspecific.data.readerId_off)) =
 | 
			
		||||
    nn_hton_entityid (to_entityid (NN_ENTITYID_UNKNOWN));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static nn_entityid_t load_readerId (const struct nn_xmsg *m)
 | 
			
		||||
static ddsi_entityid_t load_readerId (const struct nn_xmsg *m)
 | 
			
		||||
{
 | 
			
		||||
  assert (m->kind == NN_XMSG_KIND_DATA_REXMIT);
 | 
			
		||||
  assert (m->kindspecific.data.readerId_off != 0);
 | 
			
		||||
  return nn_ntoh_entityid (*((nn_entityid_t *) (m->data->payload + m->kindspecific.data.readerId_off)));
 | 
			
		||||
  return nn_ntoh_entityid (*((ddsi_entityid_t *) (m->data->payload + m->kindspecific.data.readerId_off)));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int readerId_compatible (const struct nn_xmsg *m, const struct nn_xmsg *madd)
 | 
			
		||||
{
 | 
			
		||||
  nn_entityid_t e = load_readerId (m);
 | 
			
		||||
  nn_entityid_t eadd = load_readerId (madd);
 | 
			
		||||
  ddsi_entityid_t e = load_readerId (m);
 | 
			
		||||
  ddsi_entityid_t eadd = load_readerId (madd);
 | 
			
		||||
  return e.u == NN_ENTITYID_UNKNOWN || e.u == eadd.u;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -750,13 +750,13 @@ int nn_xmsg_setencoderid (struct nn_xmsg *msg, uint32_t encoderid)
 | 
			
		|||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
void nn_xmsg_setwriterseq (struct nn_xmsg *msg, const nn_guid_t *wrguid, seqno_t wrseq)
 | 
			
		||||
void nn_xmsg_setwriterseq (struct nn_xmsg *msg, const ddsi_guid_t *wrguid, seqno_t wrseq)
 | 
			
		||||
{
 | 
			
		||||
  msg->kindspecific.data.wrguid = *wrguid;
 | 
			
		||||
  msg->kindspecific.data.wrseq = wrseq;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nn_xmsg_setwriterseq_fragid (struct nn_xmsg *msg, const nn_guid_t *wrguid, seqno_t wrseq, nn_fragment_number_t wrfragid)
 | 
			
		||||
void nn_xmsg_setwriterseq_fragid (struct nn_xmsg *msg, const ddsi_guid_t *wrguid, seqno_t wrseq, nn_fragment_number_t wrfragid)
 | 
			
		||||
{
 | 
			
		||||
  nn_xmsg_setwriterseq (msg, wrguid, wrseq);
 | 
			
		||||
  msg->kindspecific.data.wrfragid = wrfragid;
 | 
			
		||||
| 
						 | 
				
			
			@ -838,7 +838,7 @@ int nn_xmsg_addpar_sentinel_ifparam (struct nn_xmsg * m)
 | 
			
		|||
 | 
			
		||||
static void nn_xmsg_chain_release (struct q_globals *gv, struct nn_xmsg_chain *chain)
 | 
			
		||||
{
 | 
			
		||||
  nn_guid_t wrguid;
 | 
			
		||||
  ddsi_guid_t wrguid;
 | 
			
		||||
  memset (&wrguid, 0, sizeof (wrguid));
 | 
			
		||||
 | 
			
		||||
  while (chain->latest)
 | 
			
		||||
| 
						 | 
				
			
			@ -1385,7 +1385,7 @@ static int nn_xpack_mayaddmsg (const struct nn_xpack *xp, const struct nn_xmsg *
 | 
			
		|||
  return addressing_info_eq_onesidederr (xp, m);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int guid_prefix_eq (const nn_guid_prefix_t *a, const nn_guid_prefix_t *b)
 | 
			
		||||
static int guid_prefix_eq (const ddsi_guid_prefix_t *a, const ddsi_guid_prefix_t *b)
 | 
			
		||||
{
 | 
			
		||||
  return a->u[0] == b->u[0] && a->u[1] == b->u[1] && a->u[2] == b->u[2];
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1395,7 +1395,7 @@ int nn_xpack_addmsg (struct nn_xpack *xp, struct nn_xmsg *m, const uint32_t flag
 | 
			
		|||
  /* Returns > 0 if pack got sent out before adding m */
 | 
			
		||||
  struct q_globals const * const gv = xp->gv;
 | 
			
		||||
  static InfoDST_t static_zero_dst = {
 | 
			
		||||
    { SMID_INFO_DST, (DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN ? SMFLAG_ENDIANNESS : 0), sizeof (nn_guid_prefix_t) },
 | 
			
		||||
    { SMID_INFO_DST, (DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN ? SMFLAG_ENDIANNESS : 0), sizeof (ddsi_guid_prefix_t) },
 | 
			
		||||
    { { 0,0,0,0, 0,0,0,0, 0,0,0,0 } }
 | 
			
		||||
  };
 | 
			
		||||
  InfoDST_t *dst;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										22
									
								
								src/core/ddsi/tests/CMakeLists.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								src/core/ddsi/tests/CMakeLists.txt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,22 @@
 | 
			
		|||
#
 | 
			
		||||
# Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
 | 
			
		||||
#
 | 
			
		||||
# This program and the accompanying materials are made available under the
 | 
			
		||||
# terms of the Eclipse Public License v. 2.0 which is available at
 | 
			
		||||
# http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
 | 
			
		||||
# v. 1.0 which is available at
 | 
			
		||||
# http://www.eclipse.org/org/documents/edl-v10.php.
 | 
			
		||||
#
 | 
			
		||||
# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
 | 
			
		||||
#
 | 
			
		||||
include(CUnit)
 | 
			
		||||
 | 
			
		||||
set(ddsi_test_sources
 | 
			
		||||
    "plist_generic.c"
 | 
			
		||||
    "plist.c")
 | 
			
		||||
 | 
			
		||||
add_cunit_executable(cunit_ddsi ${ddsi_test_sources})
 | 
			
		||||
target_include_directories(
 | 
			
		||||
  cunit_ddsi PRIVATE
 | 
			
		||||
  "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../../ddsi/include/>")
 | 
			
		||||
target_link_libraries(cunit_ddsi PRIVATE ddsc)
 | 
			
		||||
							
								
								
									
										170
									
								
								src/core/ddsi/tests/plist.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										170
									
								
								src/core/ddsi/tests/plist.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,170 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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 "CUnit/Theory.h"
 | 
			
		||||
#include "dds/ddsrt/heap.h"
 | 
			
		||||
#include "dds/ddsrt/string.h"
 | 
			
		||||
#include "dds/ddsrt/endian.h"
 | 
			
		||||
#include "dds/ddsi/q_xqos.h"
 | 
			
		||||
#include "dds/ddsi/q_plist.h"
 | 
			
		||||
 | 
			
		||||
CU_Test (ddsi_plist, unalias_copy_merge)
 | 
			
		||||
{
 | 
			
		||||
  /* one int, one string and one string sequence covers most cases */
 | 
			
		||||
  nn_plist_t p0, p0memcpy;
 | 
			
		||||
  char *p0strs[3];
 | 
			
		||||
  nn_plist_init_empty (&p0);
 | 
			
		||||
  p0.present = PP_PRISMTECH_PROCESS_ID | PP_ENTITY_NAME;
 | 
			
		||||
  p0.aliased = PP_ENTITY_NAME;
 | 
			
		||||
  p0.process_id = 0x12345678;
 | 
			
		||||
  p0.entity_name = "nemo";
 | 
			
		||||
  p0.qos.present = QP_PARTITION;
 | 
			
		||||
  p0.qos.aliased = QP_PARTITION;
 | 
			
		||||
  p0.qos.partition.n = 3;
 | 
			
		||||
  p0.qos.partition.strs = ddsrt_malloc (p0.qos.partition.n * sizeof (*p0.qos.partition.strs));
 | 
			
		||||
  p0strs[0] = p0.qos.partition.strs[0] = "aap";
 | 
			
		||||
  p0strs[1] = p0.qos.partition.strs[1] = "noot";
 | 
			
		||||
  p0strs[2] = p0.qos.partition.strs[2] = "mies";
 | 
			
		||||
  memcpy (&p0memcpy, &p0, sizeof (p0));
 | 
			
		||||
 | 
			
		||||
  /* manually alias one, so we can free it*/
 | 
			
		||||
  nn_plist_t p0alias;
 | 
			
		||||
  memcpy (&p0alias, &p0, sizeof (p0));
 | 
			
		||||
  p0alias.qos.partition.strs = ddsrt_memdup (p0alias.qos.partition.strs, p0.qos.partition.n * sizeof (*p0.qos.partition.strs));
 | 
			
		||||
  nn_plist_fini (&p0alias);
 | 
			
		||||
  CU_ASSERT (memcmp (&p0, &p0memcpy, sizeof (p0)) == 0);
 | 
			
		||||
  CU_ASSERT_STRING_EQUAL (p0.entity_name, "nemo");
 | 
			
		||||
  CU_ASSERT_STRING_EQUAL (p0.qos.partition.strs[0], p0strs[0]);
 | 
			
		||||
  CU_ASSERT_STRING_EQUAL (p0.qos.partition.strs[1], p0strs[1]);
 | 
			
		||||
  CU_ASSERT_STRING_EQUAL (p0.qos.partition.strs[2], p0strs[2]);
 | 
			
		||||
 | 
			
		||||
  /* copy an aliased one; the original must be unchanged, the copy unaliased */
 | 
			
		||||
  nn_plist_t p1;
 | 
			
		||||
  nn_plist_init_empty (&p1);
 | 
			
		||||
  nn_plist_copy (&p1, &p0);
 | 
			
		||||
  CU_ASSERT (memcmp (&p0, &p0memcpy, sizeof (p0)) == 0);
 | 
			
		||||
  CU_ASSERT (p1.present == p0.present);
 | 
			
		||||
  CU_ASSERT (p1.aliased == 0);
 | 
			
		||||
  CU_ASSERT (p1.qos.present == p0.qos.present);
 | 
			
		||||
  CU_ASSERT (p1.qos.aliased == 0);
 | 
			
		||||
  CU_ASSERT (p1.process_id == p0.process_id);
 | 
			
		||||
  CU_ASSERT (p1.entity_name != p0.entity_name);
 | 
			
		||||
  CU_ASSERT_STRING_EQUAL (p1.entity_name, p0.entity_name);
 | 
			
		||||
  CU_ASSERT (p1.qos.partition.n == p0.qos.partition.n);
 | 
			
		||||
  CU_ASSERT (p1.qos.partition.strs != p0.qos.partition.strs);
 | 
			
		||||
  CU_ASSERT (p1.qos.partition.strs[0] != p0.qos.partition.strs[0]);
 | 
			
		||||
  CU_ASSERT (p1.qos.partition.strs[1] != p0.qos.partition.strs[1]);
 | 
			
		||||
  CU_ASSERT (p1.qos.partition.strs[2] != p0.qos.partition.strs[2]);
 | 
			
		||||
  CU_ASSERT_STRING_EQUAL (p1.qos.partition.strs[0], p0.qos.partition.strs[0]);
 | 
			
		||||
  CU_ASSERT_STRING_EQUAL (p1.qos.partition.strs[1], p0.qos.partition.strs[1]);
 | 
			
		||||
  CU_ASSERT_STRING_EQUAL (p1.qos.partition.strs[2], p0.qos.partition.strs[2]);
 | 
			
		||||
 | 
			
		||||
  /* merge-in missing ones from an aliased copy: original must remain unchanged;
 | 
			
		||||
     existing ones should stay without touching "aliased" only new ones are
 | 
			
		||||
     added as unaliased ones */
 | 
			
		||||
  nn_plist_t p2, p2memcpy;
 | 
			
		||||
  nn_plist_init_empty (&p2);
 | 
			
		||||
  p2.present = PP_ENTITY_NAME;
 | 
			
		||||
  p2.aliased = PP_ENTITY_NAME;
 | 
			
		||||
  p2.entity_name = "omen";
 | 
			
		||||
  memcpy (&p2memcpy, &p2, sizeof (p2));
 | 
			
		||||
  nn_plist_mergein_missing (&p2, &p0, p0.present, p0.qos.present);
 | 
			
		||||
  CU_ASSERT (memcmp (&p0, &p0memcpy, sizeof (p0)) == 0);
 | 
			
		||||
  CU_ASSERT (p2.present == p0.present);
 | 
			
		||||
  CU_ASSERT (p2.aliased == p2memcpy.aliased);
 | 
			
		||||
  CU_ASSERT (p2.qos.present == p0.qos.present);
 | 
			
		||||
  CU_ASSERT (p2.qos.aliased == p2memcpy.qos.aliased);
 | 
			
		||||
  CU_ASSERT (p2.process_id == p0.process_id);
 | 
			
		||||
  CU_ASSERT (p2.entity_name == p2memcpy.entity_name);
 | 
			
		||||
  CU_ASSERT_STRING_EQUAL (p2.entity_name, "omen");
 | 
			
		||||
  CU_ASSERT (p2.qos.partition.n == p0.qos.partition.n);
 | 
			
		||||
  CU_ASSERT (p2.qos.partition.strs != p0.qos.partition.strs);
 | 
			
		||||
  CU_ASSERT (p2.qos.partition.strs[0] != p0.qos.partition.strs[0]);
 | 
			
		||||
  CU_ASSERT (p2.qos.partition.strs[1] != p0.qos.partition.strs[1]);
 | 
			
		||||
  CU_ASSERT (p2.qos.partition.strs[2] != p0.qos.partition.strs[2]);
 | 
			
		||||
  CU_ASSERT_STRING_EQUAL (p2.qos.partition.strs[0], p0.qos.partition.strs[0]);
 | 
			
		||||
  CU_ASSERT_STRING_EQUAL (p2.qos.partition.strs[1], p0.qos.partition.strs[1]);
 | 
			
		||||
  CU_ASSERT_STRING_EQUAL (p2.qos.partition.strs[2], p0.qos.partition.strs[2]);
 | 
			
		||||
 | 
			
		||||
  /* unalias of p0, partition.strs mustn't change, because it, unlike its elements, wasn't aliased */
 | 
			
		||||
  nn_plist_unalias (&p0);
 | 
			
		||||
  CU_ASSERT (p0.present == p0memcpy.present);
 | 
			
		||||
  CU_ASSERT (p0.aliased == 0);
 | 
			
		||||
  CU_ASSERT (p0.qos.present == p0memcpy.qos.present);
 | 
			
		||||
  CU_ASSERT (p0.qos.aliased == 0);
 | 
			
		||||
  CU_ASSERT (p0.process_id == p0memcpy.process_id);
 | 
			
		||||
  CU_ASSERT (p0.entity_name != p0memcpy.entity_name);
 | 
			
		||||
  CU_ASSERT_STRING_EQUAL (p0.entity_name, p0memcpy.entity_name);
 | 
			
		||||
  CU_ASSERT (p0.qos.partition.n == p0memcpy.qos.partition.n);
 | 
			
		||||
  CU_ASSERT (p0.qos.partition.strs == p0memcpy.qos.partition.strs);
 | 
			
		||||
  CU_ASSERT (p0.qos.partition.strs[0] != p0strs[0]);
 | 
			
		||||
  CU_ASSERT (p0.qos.partition.strs[1] != p0strs[1]);
 | 
			
		||||
  CU_ASSERT (p0.qos.partition.strs[2] != p0strs[2]);
 | 
			
		||||
  CU_ASSERT_STRING_EQUAL (p0.qos.partition.strs[0], p0strs[0]);
 | 
			
		||||
  CU_ASSERT_STRING_EQUAL (p0.qos.partition.strs[1], p0strs[1]);
 | 
			
		||||
  CU_ASSERT_STRING_EQUAL (p0.qos.partition.strs[2], p0strs[2]);
 | 
			
		||||
  memcpy (&p0memcpy, &p0, sizeof (p0));
 | 
			
		||||
 | 
			
		||||
  /* copy an aliased one; the original must be unchanged, the copy unaliased */
 | 
			
		||||
  nn_plist_t p3;
 | 
			
		||||
  nn_plist_init_empty (&p3);
 | 
			
		||||
  nn_plist_copy (&p3, &p0);
 | 
			
		||||
  CU_ASSERT (memcmp (&p0, &p0memcpy, sizeof (p0)) == 0);
 | 
			
		||||
  CU_ASSERT (p3.present == p0.present);
 | 
			
		||||
  CU_ASSERT (p3.aliased == 0);
 | 
			
		||||
  CU_ASSERT (p3.qos.present == p0.qos.present);
 | 
			
		||||
  CU_ASSERT (p3.qos.aliased == 0);
 | 
			
		||||
  CU_ASSERT (p3.process_id == p0.process_id);
 | 
			
		||||
  CU_ASSERT (p3.entity_name != p0.entity_name);
 | 
			
		||||
  CU_ASSERT_STRING_EQUAL (p3.entity_name, p0.entity_name);
 | 
			
		||||
  CU_ASSERT (p3.qos.partition.n == p0.qos.partition.n);
 | 
			
		||||
  CU_ASSERT (p3.qos.partition.strs != p0.qos.partition.strs);
 | 
			
		||||
  CU_ASSERT (p3.qos.partition.strs[0] != p0.qos.partition.strs[0]);
 | 
			
		||||
  CU_ASSERT (p3.qos.partition.strs[1] != p0.qos.partition.strs[1]);
 | 
			
		||||
  CU_ASSERT (p3.qos.partition.strs[2] != p0.qos.partition.strs[2]);
 | 
			
		||||
  CU_ASSERT_STRING_EQUAL (p3.qos.partition.strs[0], p0.qos.partition.strs[0]);
 | 
			
		||||
  CU_ASSERT_STRING_EQUAL (p3.qos.partition.strs[1], p0.qos.partition.strs[1]);
 | 
			
		||||
  CU_ASSERT_STRING_EQUAL (p3.qos.partition.strs[2], p0.qos.partition.strs[2]);
 | 
			
		||||
 | 
			
		||||
  /* merge-in missing ones from an aliased copy: original must remain unchanged;
 | 
			
		||||
     existing ones should stay without touching "aliased" only new ones are
 | 
			
		||||
     added as unaliased ones */
 | 
			
		||||
  nn_plist_t p4, p4memcpy;
 | 
			
		||||
  nn_plist_init_empty (&p4);
 | 
			
		||||
  p4.present = PP_ENTITY_NAME;
 | 
			
		||||
  p4.aliased = PP_ENTITY_NAME;
 | 
			
		||||
  p4.entity_name = "omen";
 | 
			
		||||
  memcpy (&p4memcpy, &p4, sizeof (p4));
 | 
			
		||||
  nn_plist_mergein_missing (&p4, &p0, p0.present, p0.qos.present);
 | 
			
		||||
  CU_ASSERT (memcmp (&p0, &p0memcpy, sizeof (p0)) == 0);
 | 
			
		||||
  CU_ASSERT (p4.present == p0.present);
 | 
			
		||||
  CU_ASSERT (p4.aliased == p4memcpy.aliased);
 | 
			
		||||
  CU_ASSERT (p4.qos.present == p0.qos.present);
 | 
			
		||||
  CU_ASSERT (p4.qos.aliased == p4memcpy.qos.aliased);
 | 
			
		||||
  CU_ASSERT (p4.process_id == p0.process_id);
 | 
			
		||||
  CU_ASSERT (p4.entity_name == p4memcpy.entity_name);
 | 
			
		||||
  CU_ASSERT_STRING_EQUAL (p4.entity_name, "omen");
 | 
			
		||||
  CU_ASSERT (p4.qos.partition.n == p0.qos.partition.n);
 | 
			
		||||
  CU_ASSERT (p4.qos.partition.strs != p0.qos.partition.strs);
 | 
			
		||||
  CU_ASSERT (p4.qos.partition.strs[0] != p0.qos.partition.strs[0]);
 | 
			
		||||
  CU_ASSERT (p4.qos.partition.strs[1] != p0.qos.partition.strs[1]);
 | 
			
		||||
  CU_ASSERT (p4.qos.partition.strs[2] != p0.qos.partition.strs[2]);
 | 
			
		||||
  CU_ASSERT_STRING_EQUAL (p4.qos.partition.strs[0], p0.qos.partition.strs[0]);
 | 
			
		||||
  CU_ASSERT_STRING_EQUAL (p4.qos.partition.strs[1], p0.qos.partition.strs[1]);
 | 
			
		||||
  CU_ASSERT_STRING_EQUAL (p4.qos.partition.strs[2], p0.qos.partition.strs[2]);
 | 
			
		||||
 | 
			
		||||
  nn_plist_fini (&p0);
 | 
			
		||||
  nn_plist_fini (&p1);
 | 
			
		||||
  nn_plist_fini (&p2);
 | 
			
		||||
  nn_plist_fini (&p3);
 | 
			
		||||
  nn_plist_fini (&p4);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										314
									
								
								src/core/ddsi/tests/plist_generic.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										314
									
								
								src/core/ddsi/tests/plist_generic.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,314 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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 "CUnit/Theory.h"
 | 
			
		||||
#include "dds/ddsrt/heap.h"
 | 
			
		||||
#include "dds/ddsrt/endian.h"
 | 
			
		||||
#include "dds/ddsi/q_xqos.h"
 | 
			
		||||
#include "dds/ddsi/ddsi_plist_generic.h"
 | 
			
		||||
 | 
			
		||||
struct desc {
 | 
			
		||||
  const enum pserop desc[20];
 | 
			
		||||
  const void *data;
 | 
			
		||||
  size_t exp_sersize;
 | 
			
		||||
  const unsigned char *exp_ser;
 | 
			
		||||
 | 
			
		||||
  /* XbPROP means expectation after deser may be different from input, if exp_data
 | 
			
		||||
     is NULL, use "data", else use "exp_data" */
 | 
			
		||||
  const void *exp_data;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct desc_invalid {
 | 
			
		||||
  const enum pserop desc[20];
 | 
			
		||||
  size_t sersize;
 | 
			
		||||
  const unsigned char *ser;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#if DDSRT_ENDIAN == DDSRT_BIG_ENDIAN
 | 
			
		||||
#define SER32(v) \
 | 
			
		||||
  (unsigned char)((uint32_t)(v) >> 24), \
 | 
			
		||||
  (unsigned char)(((uint32_t)(v) >> 16) & 0xff), \
 | 
			
		||||
  (unsigned char)(((uint32_t)(v) >> 8) & 0xff), \
 | 
			
		||||
  (unsigned char)((uint32_t)(v) & 0xff)
 | 
			
		||||
#define SER32BE(v) SER32(v)
 | 
			
		||||
#else
 | 
			
		||||
#define SER32(v) \
 | 
			
		||||
  (unsigned char)((uint32_t)(v) & 0xff), \
 | 
			
		||||
  (unsigned char)(((uint32_t)(v) >> 8) & 0xff), \
 | 
			
		||||
  (unsigned char)(((uint32_t)(v) >> 16) & 0xff), \
 | 
			
		||||
  (unsigned char)((uint32_t)(v) >> 24)
 | 
			
		||||
#define SER32BE(v) \
 | 
			
		||||
  (unsigned char)((uint32_t)(v) >> 24), \
 | 
			
		||||
  (unsigned char)(((uint32_t)(v) >> 16) & 0xff), \
 | 
			
		||||
  (unsigned char)(((uint32_t)(v) >> 8) & 0xff), \
 | 
			
		||||
  (unsigned char)((uint32_t)(v) & 0xff)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
typedef unsigned char raw[];
 | 
			
		||||
typedef uint32_t raw32[];
 | 
			
		||||
typedef ddsi_octetseq_t oseq;
 | 
			
		||||
 | 
			
		||||
struct desc descs[] = {
 | 
			
		||||
  { {XSTOP}, (raw){0}, 0, (raw){0} },
 | 
			
		||||
  { {XO,XSTOP}, &(oseq){0, NULL },       4, (raw){SER32(0)} },
 | 
			
		||||
  { {XO,XSTOP}, &(oseq){1, (raw){3} },   5, (raw){SER32(1), 3} },
 | 
			
		||||
  { {XS,XSTOP}, &(char *[]){""},         5, (raw){SER32(1), 0} },
 | 
			
		||||
  { {XS,XSTOP}, &(char *[]){"meow"},     9, (raw){SER32(5), 'm','e','o','w',0} },
 | 
			
		||||
  { {XE1,XSTOP}, (raw32){1},             4, (raw){SER32(1)} },
 | 
			
		||||
  { {XE2,XSTOP}, (raw32){2},             4, (raw){SER32(2)} },
 | 
			
		||||
  { {XE3,XSTOP}, (raw32){3},             4, (raw){SER32(3)} },
 | 
			
		||||
  { {Xi,XSTOP},   (raw32){1},            4, (raw){SER32(1)} },
 | 
			
		||||
  { {Xix2,XSTOP}, (raw32){2,3},          8, (raw){SER32(2), SER32(3)} },
 | 
			
		||||
  { {Xix3,XSTOP}, (raw32){4,5,6},       12, (raw){SER32(4), SER32(5), SER32(6)} },
 | 
			
		||||
  { {Xix4,XSTOP}, (raw32){7,8,9,10},    16, (raw){SER32(7), SER32(8), SER32(9), SER32(10)} },
 | 
			
		||||
  { {Xu,XSTOP},   (raw32){1},            4, (raw){SER32(1)} },
 | 
			
		||||
  { {Xux2,XSTOP}, (raw32){2,3},          8, (raw){SER32(2), SER32(3)} },
 | 
			
		||||
  { {Xux3,XSTOP}, (raw32){4,5,6},       12, (raw){SER32(4), SER32(5), SER32(6)} },
 | 
			
		||||
  { {Xux4,XSTOP}, (raw32){7,8,9,10},    16, (raw){SER32(7), SER32(8), SER32(9), SER32(10)} },
 | 
			
		||||
  { {Xux5,XSTOP}, (raw32){7,8,9,10,11}, 20, (raw){SER32(7), SER32(8), SER32(9), SER32(10), SER32(11)} },
 | 
			
		||||
  { {XD,XSTOP},   (uint64_t[]){314159265358979324},
 | 
			
		||||
    /* note: fractional part depends on rounding rule used for converting nanoseconds to NTP time
 | 
			
		||||
       Cyclone currently rounds up, so we have to do that too */
 | 
			
		||||
    8, (raw){SER32(314159265), SER32(1541804457)} },
 | 
			
		||||
  { {XD,XSTOP},   (uint64_t[]){DDS_NEVER},
 | 
			
		||||
    8, (raw){SER32(INT32_MAX), SER32(UINT32_MAX)} },
 | 
			
		||||
  { {XDx2,XSTOP}, (uint64_t[]){314159265358979324, 271828182845904524},
 | 
			
		||||
    16, (raw){SER32(314159265), SER32(1541804457), SER32(271828182), SER32(3633132267)} },
 | 
			
		||||
  { {Xo,XSTOP},   (raw){31},             1, (raw){31} },
 | 
			
		||||
  { {Xox2,XSTOP}, (raw){31,13},          2, (raw){31,13} },
 | 
			
		||||
  { {Xb,XSTOP},   (raw){1},              1, (raw){1} },
 | 
			
		||||
  { {Xbx2,XSTOP}, (raw){1,0},            2, (raw){1,0} },
 | 
			
		||||
  { {XG,XSTOP},   (raw32){3,4,5,0x1c1}, 16, (raw){SER32BE(3), SER32BE(4), SER32BE(5), SER32BE(0x1c1) } },
 | 
			
		||||
  { {XK,XSTOP},   (raw){1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16},
 | 
			
		||||
    16, (raw){1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16} },
 | 
			
		||||
  { {XQ,Xo,XSTOP,XSTOP}, &(oseq){3, (raw){1,2,3}},
 | 
			
		||||
    7, (raw){SER32(3), 1,2,3} },
 | 
			
		||||
  { {XQ,XS,XSTOP,XSTOP}, &(ddsi_stringseq_t){2, (char*[]){"tree","flower"}},
 | 
			
		||||
    27, (raw){SER32(2), SER32(5),'t','r','e','e',0, 0,0,0, SER32(7), 'f','l','o','w','e','r',0} },
 | 
			
		||||
  { {Xb,XQ,XbPROP,XS,Xo,XSTOP,XSTOP},
 | 
			
		||||
    &(struct{char b; oseq seq;}){1, {5, (unsigned char *)(struct{char b;char *s;uint8_t o;}[]){
 | 
			
		||||
      {0,"apple",1}, {1,"orange",2}, {0,"cherry",3}, {1,"fig",4}, {1,"prune",5}}}},
 | 
			
		||||
    43, (raw){1, 0,0,0, SER32(3),
 | 
			
		||||
      SER32(7), 'o','r','a','n','g','e',0, 2,
 | 
			
		||||
      SER32(4), 'f','i','g',0, 4, 0,0,0,
 | 
			
		||||
      SER32(6), 'p','r','u','n','e',0, 5
 | 
			
		||||
    },
 | 
			
		||||
    &(struct{char b; oseq seq;}){1, {3, (unsigned char *)(struct{char b;char *s;uint8_t o;}[]){
 | 
			
		||||
      {1,"orange",2}, {1,"fig",4}, {1,"prune",5}}}},
 | 
			
		||||
  },
 | 
			
		||||
  { {Xb,XQ,XbPROP,XS,Xo,XSTOP, Xopt,XQ,XbPROP,XS,Xo,XSTOP, XSTOP},
 | 
			
		||||
    &(struct{char b; oseq seq, seq2;}){1,
 | 
			
		||||
      {5, (unsigned char *)(struct{char b;char *s;uint8_t o;}[]){
 | 
			
		||||
        {0,"apple",1}, {1,"orange",2}, {0,"cherry",3}, {1,"fig",4}, {1,"prune",5}}},
 | 
			
		||||
      {2, (unsigned char *)(struct{char b;char *s;uint8_t o;}[]){
 | 
			
		||||
        {1,"oak",8}, {0,"beech",9}}}
 | 
			
		||||
    },
 | 
			
		||||
    57, (raw){1, 0,0,0,
 | 
			
		||||
      SER32(3),
 | 
			
		||||
      SER32(7), 'o','r','a','n','g','e',0, 2,
 | 
			
		||||
      SER32(4), 'f','i','g',0, 4, 0,0,0,
 | 
			
		||||
      SER32(6), 'p','r','u','n','e',0, 5,
 | 
			
		||||
      0,
 | 
			
		||||
      SER32(1),
 | 
			
		||||
      SER32(4), 'o','a','k',0, 8
 | 
			
		||||
    },
 | 
			
		||||
    &(struct{char b; oseq seq, seq2;}){1,
 | 
			
		||||
      {3, (unsigned char *)(struct{char b;char *s;uint8_t o;}[]){
 | 
			
		||||
        {1,"orange",2}, {1,"fig",4}, {1,"prune",5}}},
 | 
			
		||||
      {1,  (unsigned char *)(struct{char b;char *s;uint8_t o;}[]){
 | 
			
		||||
        {1,"oak",8}}}
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
CU_Test (ddsi_plist_generic, ser_and_deser)
 | 
			
		||||
{
 | 
			
		||||
  union {
 | 
			
		||||
    uint64_t u;
 | 
			
		||||
    void *p;
 | 
			
		||||
    char buf[256];
 | 
			
		||||
  } mem;
 | 
			
		||||
 | 
			
		||||
  for (size_t i = 0; i < sizeof (descs) / sizeof (descs[0]); i++)
 | 
			
		||||
  {
 | 
			
		||||
    size_t memsize;
 | 
			
		||||
    void *ser;
 | 
			
		||||
    size_t sersize;
 | 
			
		||||
    dds_return_t ret;
 | 
			
		||||
    ret = plist_ser_generic (&ser, &sersize, descs[i].data, descs[i].desc);
 | 
			
		||||
    if (ret != DDS_RETCODE_OK)
 | 
			
		||||
      CU_ASSERT_FATAL (ret == DDS_RETCODE_OK);
 | 
			
		||||
    if (sersize != descs[i].exp_sersize)
 | 
			
		||||
      CU_ASSERT (sersize == descs[i].exp_sersize);
 | 
			
		||||
    /* if sizes don't match, still check prefix */
 | 
			
		||||
    size_t cmpsize = (sersize < descs[i].exp_sersize) ? sersize : descs[i].exp_sersize;
 | 
			
		||||
    if (memcmp (ser, descs[i].exp_ser, cmpsize) != 0)
 | 
			
		||||
    {
 | 
			
		||||
      printf ("memcmp i = %zu\n", i);
 | 
			
		||||
      for (size_t k = 0; k < cmpsize; k++)
 | 
			
		||||
        printf ("  %3zu  %02x  %02x\n", k, ((unsigned char *)ser)[k], descs[i].exp_ser[k]);
 | 
			
		||||
      CU_ASSERT (!(bool)"memcmp");
 | 
			
		||||
    }
 | 
			
		||||
    /* check */
 | 
			
		||||
    memsize = plist_memsize_generic (descs[i].desc);
 | 
			
		||||
    if (memsize > sizeof (mem))
 | 
			
		||||
      CU_ASSERT_FATAL (memsize <= sizeof (mem));
 | 
			
		||||
    /* memset to zero for used part so padding is identical to compiler inserted padding,
 | 
			
		||||
       but to something unlikely for the remainder */
 | 
			
		||||
    memset (mem.buf, 0, memsize);
 | 
			
		||||
    memset (mem.buf + memsize, 0xee, sizeof (mem) - memsize);
 | 
			
		||||
    ret = plist_deser_generic (&mem, ser, sersize, false, descs[i].desc);
 | 
			
		||||
    if (ret != DDS_RETCODE_OK)
 | 
			
		||||
      CU_ASSERT_FATAL (ret == DDS_RETCODE_OK);
 | 
			
		||||
    /* the compare function should be happy with it */
 | 
			
		||||
    if (!plist_equal_generic (descs[i].exp_data ? descs[i].exp_data : descs[i].data, &mem, descs[i].desc))
 | 
			
		||||
      CU_ASSERT (!(bool)"plist_equal_generic");
 | 
			
		||||
    /* content should be identical except when an XO, XS or XQ is present (because the first two
 | 
			
		||||
       alias the serialised form and XQ to freshly allocated memory), so we do a limited check */
 | 
			
		||||
    bool can_memcmp = true;
 | 
			
		||||
    for (const enum pserop *op = descs[i].desc; *op != XSTOP && can_memcmp; op++)
 | 
			
		||||
      if (*op == XS || *op == XO || *op == XQ)
 | 
			
		||||
        can_memcmp = false;
 | 
			
		||||
    if (can_memcmp && memcmp (descs[i].exp_data ? descs[i].exp_data : descs[i].data, &mem, memsize) != 0)
 | 
			
		||||
      CU_ASSERT (!(bool)"memcmp");
 | 
			
		||||
    /* rely on mem checkers to find memory leaks, incorrect free, etc. */
 | 
			
		||||
    plist_fini_generic (&mem, descs[i].desc, true);
 | 
			
		||||
    ddsrt_free (ser);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
CU_Test (ddsi_plist_generic, unalias)
 | 
			
		||||
{
 | 
			
		||||
  union {
 | 
			
		||||
    uint64_t u;
 | 
			
		||||
    void *p;
 | 
			
		||||
    char buf[256];
 | 
			
		||||
  } mem;
 | 
			
		||||
 | 
			
		||||
  for (size_t i = 0; i < sizeof (descs) / sizeof (descs[0]); i++)
 | 
			
		||||
  {
 | 
			
		||||
    void *ser;
 | 
			
		||||
    size_t sersize;
 | 
			
		||||
    dds_return_t ret;
 | 
			
		||||
    (void) plist_ser_generic (&ser, &sersize, descs[i].data, descs[i].desc);
 | 
			
		||||
    (void) plist_deser_generic (&mem, ser, sersize, false, descs[i].desc);
 | 
			
		||||
    /* after unaliasing, the data should be valid even when the serialised form has been overwritten or freed */
 | 
			
		||||
    ret = plist_unalias_generic (&mem, descs[i].desc);
 | 
			
		||||
    CU_ASSERT_FATAL (ret == DDS_RETCODE_OK);
 | 
			
		||||
    memset (ser, 0xee, sersize);
 | 
			
		||||
    ddsrt_free (ser);
 | 
			
		||||
    if (!plist_equal_generic (descs[i].exp_data ? descs[i].exp_data : descs[i].data, &mem, descs[i].desc))
 | 
			
		||||
      CU_ASSERT (!(bool)"plist_equal_generic");
 | 
			
		||||
    plist_fini_generic (&mem, descs[i].desc, false);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct desc_invalid descs_invalid[] = {
 | 
			
		||||
  { {Xb,XSTOP},   1, (raw){2} }, // 2 is not a valid boolean
 | 
			
		||||
  { {XS,XSTOP},   8, (raw){SER32(5), 'm','e','o','w',0} }, // short input
 | 
			
		||||
  { {XS,XSTOP},   8, (raw){SER32(4), 'm','e','o','w',0} }, // not terminated
 | 
			
		||||
  { {XG,XSTOP},  15, (raw){SER32BE(3), SER32BE(4), SER32BE(5), SER32BE(0x100) } }, // short input
 | 
			
		||||
  { {XK,XSTOP},  15, (raw){1,2,3,4,5,6,7,8,9,10,11,12,13,14,15} }, // short input
 | 
			
		||||
  { {XQ,Xo,XSTOP,XSTOP}, 7, (raw){SER32(4), 1,2,3} }, // short input
 | 
			
		||||
  { {XQ,XS,XSTOP,XSTOP}, // padding missing, short input
 | 
			
		||||
    24, (raw){SER32(2), SER32(5),'t','r','e','e',0, SER32(7), 'f','l','o','w','e','r',0} },
 | 
			
		||||
  { {Xb,XQ,XbPROP,XS,Xo,XSTOP,XSTOP},
 | 
			
		||||
    43, (raw){1, 0,0,0, SER32(3),
 | 
			
		||||
      SER32(7), 'o','r','a','n','g','e',0, 2,
 | 
			
		||||
      SER32(4), 'f','i','g',0, 4, 0,0,0,
 | 
			
		||||
      SER32(7), 'p','r','u','n','e',0, 5 // string not terminated
 | 
			
		||||
    } },
 | 
			
		||||
  { {Xb, XQ,XbPROP,XS,Xo,XSTOP, XQ,XbPROP,XS,Xo,XSTOP, XSTOP},
 | 
			
		||||
    43, (raw){1, 0,0,0,
 | 
			
		||||
      /* first sequence is valid */
 | 
			
		||||
      SER32(3),
 | 
			
		||||
      SER32(7), 'o','r','a','n','g','e',0, 2,
 | 
			
		||||
      SER32(4), 'f','i','g',0, 4, 0,0,0,
 | 
			
		||||
      SER32(6), 'p','r','u','n','e',0, 5,
 | 
			
		||||
      /* second sequence is invalid */
 | 
			
		||||
      0, /* pad */
 | 
			
		||||
      SER32(3),
 | 
			
		||||
      SER32(7), 'o','r','a','n','g','e',0, 2,
 | 
			
		||||
      SER32(4), 'f','i','g',0, 4, 0,0,0,
 | 
			
		||||
      SER32(7), 'p','r','u','n','e',0, 5 // string not terminated
 | 
			
		||||
    } }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
CU_Test (ddsi_plist_generic, invalid_input)
 | 
			
		||||
{
 | 
			
		||||
  union {
 | 
			
		||||
    uint64_t u;
 | 
			
		||||
    void *p;
 | 
			
		||||
    char buf[256];
 | 
			
		||||
  } mem;
 | 
			
		||||
 | 
			
		||||
  for (size_t i = 0; i < sizeof (descs_invalid) / sizeof (descs_invalid[0]); i++)
 | 
			
		||||
  {
 | 
			
		||||
    dds_return_t ret;
 | 
			
		||||
    ret = plist_deser_generic (&mem, descs_invalid[i].ser, descs_invalid[i].sersize, false, descs_invalid[i].desc);
 | 
			
		||||
    if (ret == DDS_RETCODE_OK)
 | 
			
		||||
      CU_ASSERT_FATAL (ret != DDS_RETCODE_OK);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
CU_Test (ddsi_plist_generic, optional)
 | 
			
		||||
{
 | 
			
		||||
  union {
 | 
			
		||||
    uint64_t u;
 | 
			
		||||
    void *p;
 | 
			
		||||
    char buf[256];
 | 
			
		||||
  } mem;
 | 
			
		||||
 | 
			
		||||
  enum pserop ser_desc[] = {Xb,XQ,XbPROP,XS,Xo,XSTOP,XSTOP};
 | 
			
		||||
  enum pserop deser_desc[] = {Xb,XQ,XbPROP,XS,Xo,XSTOP, Xopt,XQ,XbPROP,XS,Xo,XSTOP, XSTOP};
 | 
			
		||||
  const void *data = &(struct{char b; oseq seq;}){
 | 
			
		||||
    1, {5, (unsigned char *)(struct{char b;char *s;uint8_t o;}[]){
 | 
			
		||||
      {0,"apple",1}, {1,"orange",2}, {0,"cherry",3}, {1,"fig",4}, {1,"prune",5}}}};
 | 
			
		||||
  size_t exp_sersize = 43;
 | 
			
		||||
  const unsigned char *exp_ser = (raw){
 | 
			
		||||
    1, 0,0,0, SER32(3),
 | 
			
		||||
    SER32(7), 'o','r','a','n','g','e',0, 2,
 | 
			
		||||
    SER32(4), 'f','i','g',0, 4, 0,0,0,
 | 
			
		||||
    SER32(6), 'p','r','u','n','e',0, 5
 | 
			
		||||
  };
 | 
			
		||||
  const void *exp_data = &(struct{char b; oseq seq; oseq seq2;}){
 | 
			
		||||
    1, {3, (unsigned char *)(struct{char b;char *s;uint8_t o;}[]){
 | 
			
		||||
      {1,"orange",2}, {1,"fig",4}, {1,"prune",5}}},
 | 
			
		||||
    {0, NULL}};
 | 
			
		||||
 | 
			
		||||
  size_t memsize;
 | 
			
		||||
  void *ser;
 | 
			
		||||
  size_t sersize;
 | 
			
		||||
  dds_return_t ret;
 | 
			
		||||
  ret = plist_ser_generic (&ser, &sersize, data, ser_desc);
 | 
			
		||||
  CU_ASSERT_FATAL (ret == DDS_RETCODE_OK);
 | 
			
		||||
  CU_ASSERT (sersize == exp_sersize);
 | 
			
		||||
  /* if sizes don't match, still check prefix */
 | 
			
		||||
  size_t cmpsize = (sersize < exp_sersize) ? sersize : exp_sersize;
 | 
			
		||||
  if (memcmp (ser, exp_ser, cmpsize) != 0)
 | 
			
		||||
  {
 | 
			
		||||
    printf ("ddsi_plist_generic_optional: memcmp\n");
 | 
			
		||||
    for (size_t k = 0; k < cmpsize; k++)
 | 
			
		||||
      printf ("  %3zu  %02x  %02x\n", k, ((unsigned char *)ser)[k], exp_ser[k]);
 | 
			
		||||
    CU_ASSERT (!(bool)"memcmp");
 | 
			
		||||
  }
 | 
			
		||||
  /* check */
 | 
			
		||||
  memsize = plist_memsize_generic (deser_desc);
 | 
			
		||||
  CU_ASSERT_FATAL (memsize <= sizeof (mem));
 | 
			
		||||
  memset (&mem, 0xee, sizeof (mem));
 | 
			
		||||
  ret = plist_deser_generic (&mem, ser, sersize, false, deser_desc);
 | 
			
		||||
  CU_ASSERT_FATAL (ret == DDS_RETCODE_OK);
 | 
			
		||||
  /* the compare function should be happy with it */
 | 
			
		||||
  CU_ASSERT (plist_equal_generic (exp_data, &mem, deser_desc));
 | 
			
		||||
  plist_fini_generic (&mem, deser_desc, true);
 | 
			
		||||
  ddsrt_free (ser);
 | 
			
		||||
}
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show more
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue