Merge branch 'master' into merge

Signed-off-by: Martin Bremmer <martin.bremmer@adlinktech.com>
This commit is contained in:
Martin Bremmer 2019-09-27 14:10:10 +02:00
commit 919850232c
128 changed files with 6936 additions and 2075 deletions

View file

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

View file

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

View file

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

View file

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

View file

@ -18,8 +18,7 @@
extern "C" {
#endif
DDS_EXPORT dds_return_t dds_domain_create (dds_domain **domain_out, dds_domainid_t id);
DDS_EXPORT void dds_domain_free (dds_domain *domain);
DDS_EXPORT dds_return_t dds_domain_create_internal (dds_domain **domain_out, dds_domainid_t id, bool use_existing, const char *config) ddsrt_nonnull((1,4));
DDS_EXPORT dds_domain *dds_domain_find_locked (dds_domainid_t id);
#if defined (__cplusplus)

View file

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

View file

@ -69,6 +69,13 @@ typedef int32_t dds_handle_t;
* This handlelink is invalid after the related handle is deleted and should
* never be used afterwards.
*/
/* Closing & closed can be combined, but having two gives a means for enforcing
that close() be called first, then close_wait(), and then delete(). */
#define HDL_FLAG_CLOSING (0x80000000u)
#define HDL_FLAG_CLOSED (0x40000000u)
#define HDL_FLAG_PENDING (0x20000000u)
struct dds_handle_link {
dds_handle_t hdl;
ddsrt_atomic_uint32_t cnt_flags;
@ -112,6 +119,15 @@ dds_handle_create(
struct dds_handle_link *link);
/*
* Register a specific handle.
*/
DDS_EXPORT dds_return_t
dds_handle_register_special (
struct dds_handle_link *link, dds_handle_t handle);
DDS_EXPORT void dds_handle_unpend (struct dds_handle_link *link);
/*
* This will close the handle. All information remains, only new claims will
* fail.
@ -119,10 +135,9 @@ dds_handle_create(
* This is a noop on an already closed handle.
*/
DDS_EXPORT void
dds_handle_close(
dds_handle_close_wait (
struct dds_handle_link *link);
/*
* This will remove the handle related information from the server administration
* to free up space.
@ -134,8 +149,7 @@ dds_handle_close(
*/
DDS_EXPORT int32_t
dds_handle_delete(
struct dds_handle_link *link,
dds_time_t timeout);
struct dds_handle_link *link);
/*
@ -149,6 +163,11 @@ dds_handle_pin(
dds_handle_t hdl,
struct dds_handle_link **entity);
DDS_EXPORT int32_t
dds_handle_pin_and_ref(
dds_handle_t hdl,
struct dds_handle_link **entity);
DDS_EXPORT void
dds_handle_repin(
@ -172,14 +191,15 @@ dds_handle_unpin(
* break of your process and release the handle, making the deletion
* possible.
*/
DDS_EXPORT bool
dds_handle_is_closed(
struct dds_handle_link *link);
DDS_EXPORT void dds_handle_add_ref (struct dds_handle_link *link);
DDS_EXPORT bool dds_handle_drop_ref (struct dds_handle_link *link);
DDS_EXPORT inline bool dds_handle_is_closed (struct dds_handle_link *link) {
return (ddsrt_atomic_ld32 (&link->cnt_flags) & (HDL_FLAG_CLOSED | HDL_FLAG_CLOSING)) != 0;
}
#if defined (__cplusplus)
}
#endif

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -11,14 +11,14 @@
*/
#include <string.h>
#include "dds/ddsrt/environ.h"
#include "dds/ddsrt/process.h"
#include "dds/ddsrt/heap.h"
#include "dds__init.h"
#include "dds__rhc.h"
#include "dds/ddsc/dds_rhc.h"
#include "dds__domain.h"
#include "dds__builtin.h"
#include "dds__whc_builtintopic.h"
#include "dds__entity.h"
#include "dds/ddsi/ddsi_iid.h"
#include "dds/ddsi/ddsi_tkmap.h"
#include "dds/ddsi/ddsi_serdata.h"
@ -27,7 +27,16 @@
#include "dds/ddsi/q_config.h"
#include "dds/ddsi/q_gc.h"
#include "dds/ddsi/q_globals.h"
#include "dds/version.h"
static dds_return_t dds_domain_free (dds_entity *vdomain);
const struct dds_entity_deriver dds_entity_deriver_domain = {
.interrupt = dds_entity_deriver_dummy_interrupt,
.close = dds_entity_deriver_dummy_close,
.delete = dds_domain_free,
.set_qos = dds_entity_deriver_dummy_set_qos,
.validate_status = dds_entity_deriver_dummy_validate_status
};
static int dds_domain_compare (const void *va, const void *vb)
{
@ -39,14 +48,20 @@ static int dds_domain_compare (const void *va, const void *vb)
static const ddsrt_avl_treedef_t dds_domaintree_def = DDSRT_AVL_TREEDEF_INITIALIZER (
offsetof (dds_domain, m_node), offsetof (dds_domain, m_id), dds_domain_compare, 0);
static dds_return_t dds_domain_init (dds_domain *domain, dds_domainid_t domain_id)
static dds_return_t dds_domain_init (dds_domain *domain, dds_domainid_t domain_id, const char *config)
{
dds_return_t ret = DDS_RETCODE_OK;
char * uri = NULL;
uint32_t len;
dds_entity_t domain_handle;
if ((domain_handle = dds_entity_init (&domain->m_entity, &dds_global.m_entity, DDS_KIND_DOMAIN, NULL, NULL, 0)) < 0)
return domain_handle;
domain->m_entity.m_domain = domain;
domain->m_entity.m_flags |= DDS_ENTITY_IMPLICIT;
domain->m_entity.m_iid = ddsi_iid_gen ();
domain->gv.tstart = now ();
domain->m_refc = 1;
ddsrt_avl_init (&dds_topictree_def, &domain->m_topics);
/* | domain_id | domain id in config | result
@ -72,8 +87,7 @@ static dds_return_t dds_domain_init (dds_domain *domain, dds_domainid_t domain_i
a value (if nothing has been set previously, it a warning is good
enough) */
(void) ddsrt_getenv ("CYCLONEDDS_URI", &uri);
domain->cfgst = config_init (uri, &domain->gv.config, domain_id);
domain->cfgst = config_init (config, &domain->gv.config, domain_id);
if (domain->cfgst == NULL)
{
DDS_ILOG (DDS_LC_CONFIG, domain_id, "Failed to parse configuration XML file %s\n", uri);
@ -152,9 +166,9 @@ static dds_return_t dds_domain_init (dds_domain *domain, dds_domainid_t domain_i
if (domain->gv.config.liveliness_monitoring)
ddsi_threadmon_register_domain (dds_global.threadmon, &domain->gv);
dds_entity_init_complete (&domain->m_entity);
return DDS_RETCODE_OK;
rtps_stop (&domain->gv);
fail_rtps_start:
if (domain->gv.config.liveliness_monitoring && dds_global.threadmon_count == 1)
ddsi_threadmon_stop (dds_global.threadmon);
@ -170,43 +184,23 @@ fail_rtps_init:
fail_rtps_config:
config_fini (domain->cfgst);
fail_config:
dds_handle_delete (&domain->m_entity.m_hdllink);
return ret;
}
static void dds_domain_fini (struct dds_domain *domain)
{
rtps_stop (&domain->gv);
dds__builtin_fini (domain);
if (domain->gv.config.liveliness_monitoring)
ddsi_threadmon_unregister_domain (dds_global.threadmon, &domain->gv);
rtps_fini (&domain->gv);
ddsrt_mutex_lock (&dds_global.m_mutex);
if (domain->gv.config.liveliness_monitoring && --dds_global.threadmon_count == 0)
{
ddsi_threadmon_stop (dds_global.threadmon);
ddsi_threadmon_free (dds_global.threadmon);
}
ddsrt_mutex_unlock (&dds_global.m_mutex);
config_fini (domain->cfgst);
}
dds_domain *dds_domain_find_locked (dds_domainid_t id)
{
return ddsrt_avl_lookup (&dds_domaintree_def, &dds_global.m_domains, &id);
}
dds_return_t dds_domain_create (dds_domain **domain_out, dds_domainid_t id)
dds_return_t dds_domain_create_internal (dds_domain **domain_out, dds_domainid_t id, bool use_existing, const char *config)
{
struct dds_domain *dom = NULL;
struct dds_domain *dom;
dds_return_t ret;
/* FIXME: should perhaps lock parent object just like everywhere */
ddsrt_mutex_lock (&dds_global.m_mutex);
/* FIXME: hack around default domain ids, not yet being able to handle multiple domains simultaneously */
retry:
if (id != DDS_DOMAIN_DEFAULT)
{
if ((dom = dds_domain_find_locked (id)) == NULL)
@ -225,41 +219,94 @@ dds_return_t dds_domain_create (dds_domain **domain_out, dds_domainid_t id)
switch (ret)
{
case DDS_RETCODE_OK:
dom->m_refc++;
*domain_out = dom;
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);
}

View file

@ -40,10 +40,15 @@ const struct dds_entity_deriver *dds_entity_deriver_table[] = {
[DDS_KIND_COND_QUERY] = &dds_entity_deriver_readcondition,
[DDS_KIND_COND_GUARD] = &dds_entity_deriver_guardcondition,
[DDS_KIND_WAITSET] = &dds_entity_deriver_waitset,
[DDS_KIND_DOMAIN] = &dds_entity_deriver_domain,
[DDS_KIND_CYCLONEDDS] = &dds_entity_deriver_cyclonedds
};
dds_return_t dds_entity_deriver_dummy_close (struct dds_entity *e) {
(void) e; return DDS_RETCODE_OK;
void dds_entity_deriver_dummy_interrupt (struct dds_entity *e) {
(void) e;
}
void dds_entity_deriver_dummy_close (struct dds_entity *e) {
(void) e;
}
dds_return_t dds_entity_deriver_dummy_delete (struct dds_entity *e) {
(void) e; return DDS_RETCODE_OK;
@ -55,7 +60,8 @@ dds_return_t dds_entity_deriver_dummy_validate_status (uint32_t mask) {
(void) mask; return DDS_RETCODE_ILLEGAL_OPERATION;
}
extern inline dds_return_t dds_entity_deriver_close (struct dds_entity *e);
extern inline void dds_entity_deriver_interrupt (struct dds_entity *e);
extern inline void dds_entity_deriver_close (struct dds_entity *e);
extern inline dds_return_t dds_entity_deriver_delete (struct dds_entity *e);
extern inline dds_return_t dds_entity_deriver_set_qos (struct dds_entity *e, const dds_qos_t *qos, bool enabled);
extern inline dds_return_t dds_entity_deriver_validate_status (struct dds_entity *e, uint32_t mask);
@ -73,23 +79,12 @@ const ddsrt_avl_treedef_t dds_entity_children_td = DDSRT_AVL_TREEDEF_INITIALIZER
static void dds_entity_observers_signal (dds_entity *observed, uint32_t status);
static void dds_entity_observers_signal_delete (dds_entity *observed);
static void dds_entity_observers_delete (dds_entity *observed);
void dds_entity_add_ref_locked (dds_entity *e)
{
dds_handle_add_ref (&e->m_hdllink);
}
dds_domain *dds__entity_domain (dds_entity *e)
{
return e->m_domain;
}
static dds_entity *dds__nonself_parent (dds_entity *e)
{
return e->m_parent == e ? NULL : e->m_parent;
}
static bool entity_has_status (const dds_entity *e)
{
switch (e->m_kind)
@ -105,6 +100,8 @@ static bool entity_has_status (const dds_entity *e)
case DDS_KIND_COND_QUERY:
case DDS_KIND_COND_GUARD:
case DDS_KIND_WAITSET:
case DDS_KIND_DOMAIN:
case DDS_KIND_CYCLONEDDS:
break;
case DDS_KIND_DONTCARE:
abort ();
@ -117,12 +114,13 @@ dds_entity_t dds_entity_init (dds_entity *e, dds_entity *parent, dds_entity_kind
{
dds_handle_t handle;
assert ((kind == DDS_KIND_PARTICIPANT) == (parent == NULL));
assert ((kind == DDS_KIND_CYCLONEDDS) == (parent == NULL));
assert (e);
e->m_kind = kind;
e->m_qos = qos;
e->m_cb_count = 0;
e->m_cb_pending_count = 0;
e->m_observers = NULL;
/* TODO: CHAM-96: Implement dynamic enabling of entity. */
@ -143,14 +141,14 @@ dds_entity_t dds_entity_init (dds_entity *e, dds_entity *parent, dds_entity_kind
{
e->m_parent = parent;
e->m_domain = parent->m_domain;
e->m_participant = parent->m_participant;
ddsrt_avl_init (&dds_entity_children_td, &e->m_children);
}
else
{
e->m_participant = e;
e->m_parent = e;
assert (kind == DDS_KIND_CYCLONEDDS);
e->m_parent = NULL;
e->m_domain = NULL;
}
ddsrt_avl_init (&dds_entity_children_td, &e->m_children);
dds_reset_listener (&e->m_listener);
if (listener)
@ -162,13 +160,26 @@ dds_entity_t dds_entity_init (dds_entity *e, dds_entity *parent, dds_entity_kind
ddsrt_mutex_unlock (&parent->m_observers_lock);
}
if ((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)

View file

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

View file

@ -20,27 +20,10 @@
#include "dds__handles.h"
#include "dds__types.h"
/* FIXME: this code isn't really correct when USE_CHH is set:
- the DDS entity code doesn't really play by the awake/asleep mechanism
- there is no provision in the code for a handle being deleted concurrent to a lookup,
that is, deleting handle links should also go through the GC
entity framework needs a fair bit of rewriting anyway ... */
#define USE_CHH 0
#define HDL_FLAG_CLOSED (0x80000000u)
/* ref count: # outstanding references to this handle/object (not so sure it is
ideal to have a one-to-one mapping between the two, but that is what the rest
of the code assumes at the moment); so this limits one to having, e.g., no
more than 64k endpoints referencing the same topic */
#define HDL_REFCOUNT_MASK (0x0ffff000u)
#define HDL_REFCOUNT_UNIT (0x00001000u)
#define HDL_REFCOUNT_SHIFT 12
/* pin count: # concurrent operations, so allowing up to 4096 threads had better
be enough ... */
#define HDL_PINCOUNT_MASK (0x00000fffu)
#define HDL_PINCOUNT_UNIT (0x00000001u)
/* Maximum number of handles is INT32_MAX - 1, but as the allocator relies on a
random generator for finding a free one, the time spent in the dds_handle_create
@ -50,11 +33,7 @@
#define MAX_HANDLES (INT32_MAX / 128)
struct dds_handle_server {
#if USE_CHH
struct ddsrt_chh *ht;
#else
struct ddsrt_hh *ht;
#endif
size_t count;
ddsrt_mutex_t lock;
ddsrt_cond_t cond;
@ -78,45 +57,46 @@ static int handle_equal (const void *va, const void *vb)
dds_return_t dds_handle_server_init (void)
{
#if USE_CHH
handles.ht = ddsrt_chh_new (128, handle_hash, handle_equal, free_via_gc);
#else
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);

View file

@ -18,10 +18,11 @@
#include "dds/ddsrt/process.h"
#include "dds/ddsrt/heap.h"
#include "dds__init.h"
#include "dds__rhc.h"
#include "dds/ddsc/dds_rhc.h"
#include "dds__domain.h"
#include "dds__builtin.h"
#include "dds__whc_builtintopic.h"
#include "dds__entity.h"
#include "dds/ddsi/ddsi_iid.h"
#include "dds/ddsi/ddsi_tkmap.h"
#include "dds/ddsi/ddsi_serdata.h"
@ -32,10 +33,49 @@
#include "dds/ddsi/q_globals.h"
#include "dds/version.h"
#define DOMAIN_ID_MIN 0
#define DOMAIN_ID_MAX 230
static void dds_close (struct dds_entity *e);
static dds_return_t dds_fini (struct dds_entity *e);
dds_globals dds_global;
const struct dds_entity_deriver dds_entity_deriver_cyclonedds = {
.interrupt = dds_entity_deriver_dummy_interrupt,
.close = dds_close,
.delete = dds_fini,
.set_qos = dds_entity_deriver_dummy_set_qos,
.validate_status = dds_entity_deriver_dummy_validate_status
};
dds_cyclonedds_entity dds_global;
#define CDDS_STATE_ZERO 0u
#define CDDS_STATE_STARTING 1u
#define CDDS_STATE_READY 2u
#define CDDS_STATE_STOPPING 3u
static ddsrt_atomic_uint32_t dds_state = DDSRT_ATOMIC_UINT32_INIT (CDDS_STATE_ZERO);
static void common_cleanup (void)
{
if (thread_states_fini ())
dds_handle_server_fini ();
ddsi_iid_fini ();
ddsrt_cond_destroy (&dds_global.m_cond);
ddsrt_mutex_destroy (&dds_global.m_mutex);
ddsrt_atomic_st32 (&dds_state, CDDS_STATE_ZERO);
ddsrt_cond_broadcast (ddsrt_get_singleton_cond ());
}
static bool cyclonedds_entity_ready (uint32_t s)
{
assert (s != CDDS_STATE_ZERO);
if (s == CDDS_STATE_STARTING || s == CDDS_STATE_STOPPING)
return false;
else
{
struct dds_handle_link *x;
return dds_handle_pin_and_ref (DDS_CYCLONEDDS_HANDLE, &x) == DDS_RETCODE_OK;
}
}
dds_return_t dds_init (void)
{
@ -43,18 +83,34 @@ dds_return_t dds_init (void)
ddsrt_init ();
ddsrt_mutex_t * const init_mutex = ddsrt_get_singleton_mutex ();
ddsrt_cond_t * const init_cond = ddsrt_get_singleton_cond ();
ddsrt_mutex_lock (init_mutex);
if (dds_global.m_init_count++ != 0)
uint32_t s = ddsrt_atomic_ld32 (&dds_state);
while (s != CDDS_STATE_ZERO && !cyclonedds_entity_ready (s))
{
ddsrt_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;
}

View file

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

View file

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

View file

@ -12,11 +12,13 @@
#include <assert.h>
#include "dds/ddsrt/cdtors.h"
#include "dds/ddsrt/environ.h"
#include "dds/ddsi/q_entity.h"
#include "dds/ddsi/q_thread.h"
#include "dds/ddsi/q_config.h"
#include "dds/ddsi/q_plist.h"
#include "dds/ddsi/q_globals.h"
#include "dds/version.h"
#include "dds__init.h"
#include "dds__domain.h"
#include "dds__participant.h"
@ -42,14 +44,7 @@ static dds_return_t dds_participant_delete (dds_entity *e)
thread_state_awake (lookup_thread_state (), &e->m_domain->gv);
if ((ret = delete_participant (&e->m_domain->gv, &e->m_guid)) < 0)
DDS_CERROR (&e->m_domain->gv.logconfig, "dds_participant_delete: internal error %"PRId32"\n", ret);
ddsrt_mutex_lock (&dds_global.m_mutex);
ddsrt_avl_delete (&dds_entity_children_td, &e->m_domain->m_ppants, e);
ddsrt_mutex_unlock (&dds_global.m_mutex);
thread_state_asleep (lookup_thread_state ());
/* Every dds_init needs a dds_fini. */
dds_domain_free (e->m_domain);
dds_fini ();
return DDS_RETCODE_OK;
}
@ -74,6 +69,7 @@ static dds_return_t dds_participant_qos_set (dds_entity *e, const dds_qos_t *qos
}
const struct dds_entity_deriver dds_entity_deriver_participant = {
.interrupt = dds_entity_deriver_dummy_interrupt,
.close = dds_entity_deriver_dummy_close,
.delete = dds_participant_delete,
.set_qos = dds_participant_qos_set,
@ -84,16 +80,19 @@ dds_entity_t dds_create_participant (const dds_domainid_t domain, const dds_qos_
{
dds_domain *dom;
dds_entity_t ret;
nn_guid_t guid;
ddsi_guid_t guid;
dds_participant * pp;
nn_plist_t plist;
dds_qos_t *new_qos = NULL;
char *config = "";
/* Make sure DDS instance is initialized. */
if ((ret = dds_init ()) < 0)
goto err_dds_init;
if ((ret = dds_domain_create (&dom, domain)) < 0)
(void) ddsrt_getenv (DDS_PROJECT_NAME_NOSPACE_CAPS"_URI", &config);
if ((ret = dds_domain_create_internal (&dom, domain, true, config)) < 0)
goto err_domain_create;
new_qos = dds_create_qos ();
@ -118,7 +117,7 @@ dds_entity_t dds_create_participant (const dds_domainid_t domain, const dds_qos_
}
pp = dds_alloc (sizeof (*pp));
if ((ret = dds_entity_init (&pp->m_entity, NULL, DDS_KIND_PARTICIPANT, new_qos, listener, DDS_PARTICIPANT_STATUS_MASK)) < 0)
if ((ret = dds_entity_init (&pp->m_entity, &dom->m_entity, DDS_KIND_PARTICIPANT, new_qos, listener, DDS_PARTICIPANT_STATUS_MASK)) < 0)
goto err_entity_init;
pp->m_entity.m_guid = guid;
@ -127,9 +126,14 @@ dds_entity_t dds_create_participant (const dds_domainid_t domain, const dds_qos_
pp->m_builtin_subscriber = 0;
/* Add participant to extent */
ddsrt_mutex_lock (&dds_global.m_mutex);
ddsrt_avl_insert (&dds_entity_children_td, &dom->m_ppants, &pp->m_entity);
ddsrt_mutex_unlock (&dds_global.m_mutex);
ddsrt_mutex_lock (&dds_global.m_entity.m_mutex);
dds_entity_register_child (&dom->m_entity, &pp->m_entity);
ddsrt_mutex_unlock (&dds_global.m_entity.m_mutex);
dds_entity_init_complete (&pp->m_entity);
/* drop temporary extra ref to domain, dds_init */
dds_delete (dom->m_entity.m_hdllink.hdl);
dds_delete_impl_pinned (&dds_global.m_entity, DIS_EXPLICIT);
return ret;
err_entity_init:
@ -137,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;
}

View file

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

View file

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

View file

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

View file

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

View file

@ -18,7 +18,7 @@
#include "dds__reader.h"
#include "dds__listener.h"
#include "dds__init.h"
#include "dds__rhc.h"
#include "dds/ddsc/dds_rhc.h"
#include "dds__rhc_default.h"
#include "dds__topic.h"
#include "dds__get_status.h"
@ -40,16 +40,21 @@ DECL_ENTITY_LOCK_UNLOCK (extern inline, dds_reader)
DDS_SAMPLE_LOST_STATUS |\
DDS_SUBSCRIPTION_MATCHED_STATUS)
static dds_return_t dds_reader_close (dds_entity *e) ddsrt_nonnull_all;
static void dds_reader_close (dds_entity *e) ddsrt_nonnull_all;
static dds_return_t dds_reader_close (dds_entity *e)
static void dds_reader_close (dds_entity *e)
{
dds_return_t ret = DDS_RETCODE_OK;
struct dds_reader * const rd = (struct dds_reader *) e;
assert (rd->m_rd != NULL);
thread_state_awake (lookup_thread_state (), &e->m_domain->gv);
if (delete_reader (&e->m_domain->gv, &e->m_guid) != 0)
ret = DDS_RETCODE_ERROR;
(void) delete_reader (&e->m_domain->gv, &e->m_guid);
thread_state_asleep (lookup_thread_state ());
return ret;
ddsrt_mutex_lock (&e->m_mutex);
while (rd->m_rd != NULL)
ddsrt_cond_wait (&e->m_cond, &e->m_mutex);
ddsrt_mutex_unlock (&e->m_mutex);
}
static dds_return_t dds_reader_delete (dds_entity *e) ddsrt_nonnull_all;
@ -57,17 +62,12 @@ static dds_return_t dds_reader_delete (dds_entity *e) ddsrt_nonnull_all;
static dds_return_t dds_reader_delete (dds_entity *e)
{
dds_reader * const rd = (dds_reader *) e;
dds_return_t ret;
if ((ret = dds_delete (rd->m_topic->m_entity.m_hdllink.hdl)) == DDS_RETCODE_OK)
{
/* Delete an implicitly created parent; for normal ones, this is expected
to fail with BAD_PARAMETER - FIXME: there must be a cleaner way */
ret = dds_delete_impl (e->m_parent->m_hdllink.hdl, true);
if (ret == DDS_RETCODE_BAD_PARAMETER)
ret = DDS_RETCODE_OK;
}
(void) dds_delete (rd->m_topic->m_entity.m_hdllink.hdl);
dds_free (rd->m_loan);
return ret;
thread_state_awake (lookup_thread_state (), &e->m_domain->gv);
dds_rhc_free (rd->m_rhc);
thread_state_asleep (lookup_thread_state ());
return DDS_RETCODE_OK;
}
static dds_return_t dds_reader_qos_set (dds_entity *e, const dds_qos_t *qos, bool enabled)
@ -97,11 +97,14 @@ void dds_reader_data_available_cb (struct dds_reader *rd)
overhead really matters. Otherwise, it is pretty much like
dds_reader_status_cb. */
const bool data_av_enabled = (ddsrt_atomic_ld32 (&rd->m_entity.m_status.m_status_and_mask) & (DDS_DATA_AVAILABLE_STATUS << SAM_ENABLED_SHIFT));
if (!data_av_enabled)
const uint32_t data_av_enabled = (ddsrt_atomic_ld32 (&rd->m_entity.m_status.m_status_and_mask) & (DDS_DATA_AVAILABLE_STATUS << SAM_ENABLED_SHIFT));
if (data_av_enabled == 0)
return;
ddsrt_mutex_lock (&rd->m_entity.m_observers_lock);
rd->m_entity.m_cb_pending_count++;
/* FIXME: why wait if no listener is set? */
while (rd->m_entity.m_cb_count > 0)
ddsrt_cond_wait (&rd->m_entity.m_observers_cond, &rd->m_entity.m_observers_lock);
rd->m_entity.m_cb_count++;
@ -111,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;

View file

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

View file

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

View file

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

View file

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

View file

@ -38,6 +38,7 @@ static dds_return_t dds_subscriber_status_validate (uint32_t mask)
}
const struct dds_entity_deriver dds_entity_deriver_subscriber = {
.interrupt = dds_entity_deriver_dummy_interrupt,
.close = dds_entity_deriver_dummy_close,
.delete = dds_entity_deriver_dummy_delete,
.set_qos = dds_subscriber_qos_set,
@ -66,6 +67,7 @@ dds_entity_t dds__create_subscriber_l (dds_participant *participant, const dds_q
subscriber = dds_entity_init (&sub->m_entity, &participant->m_entity, DDS_KIND_SUBSCRIBER, new_qos, listener, DDS_SUBSCRIBER_STATUS_MASK);
sub->m_entity.m_iid = ddsi_iid_gen ();
dds_entity_register_child (&participant->m_entity, &sub->m_entity);
dds_entity_init_complete (&sub->m_entity);
return subscriber;
}

View file

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

View file

@ -1,5 +1,5 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
* Copyright(c) 2006 to 2019 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
@ -17,11 +17,10 @@
#include "dds__participant.h"
#include "dds__querycond.h"
#include "dds__readcond.h"
#include "dds__rhc.h"
#include "dds__init.h"
#include "dds/ddsc/dds_rhc.h"
#include "dds/ddsi/ddsi_iid.h"
DEFINE_ENTITY_LOCK_UNLOCK (static, dds_waitset, DDS_KIND_WAITSET)
static bool is_triggered (struct dds_entity *e)
{
bool t;
@ -63,7 +62,7 @@ static dds_return_t dds_waitset_wait_impl (dds_entity_t waitset, dds_attach_t *x
}
/* Move any previously but no longer triggering entities back to the observed list */
ddsrt_mutex_lock (&ws->m_entity.m_mutex);
ddsrt_mutex_lock (&ws->wait_lock);
ws->ntriggered = 0;
for (size_t i = 0; i < ws->nentities; i++)
{
@ -76,83 +75,195 @@ static dds_return_t dds_waitset_wait_impl (dds_entity_t waitset, dds_attach_t *x
}
/* Only wait/keep waiting when we have something to observe and there aren't any triggers yet. */
while (ws->nentities > 0 && ws->ntriggered == 0)
if (!ddsrt_cond_waituntil (&ws->m_entity.m_cond, &ws->m_entity.m_mutex, abstimeout))
while (ws->nentities > 0 && ws->ntriggered == 0 && !dds_handle_is_closed (&ws->m_entity.m_hdllink))
if (!ddsrt_cond_waituntil (&ws->wait_cond, &ws->wait_lock, abstimeout))
break;
ret = (int32_t) ws->ntriggered;
for (size_t i = 0; i < ws->ntriggered && i < nxs; i++)
xs[i] = ws->entities[i].arg;
ddsrt_mutex_unlock (&ws->m_entity.m_mutex);
ddsrt_mutex_unlock (&ws->wait_lock);
dds_entity_unpin (&ws->m_entity);
return ret;
}
static dds_return_t dds_waitset_close (struct dds_entity *e)
static void dds_waitset_interrupt (struct dds_entity *e)
{
/* deep in the process of deleting the entity, so this is the only thread */
dds_waitset *ws = (dds_waitset *) e;
for (size_t i = 0; i < ws->nentities; i++)
(void) dds_entity_observer_unregister (ws->entities[i].entity, &ws->m_entity);
return DDS_RETCODE_OK;
ddsrt_mutex_lock (&ws->wait_lock);
assert (dds_handle_is_closed (&ws->m_entity.m_hdllink));
ddsrt_cond_broadcast (&ws->wait_cond);
ddsrt_mutex_unlock (&ws->wait_lock);
}
static void dds_waitset_close (struct dds_entity *e)
{
dds_waitset *ws = (dds_waitset *) e;
ddsrt_mutex_lock (&ws->wait_lock);
while (ws->nentities > 0)
{
dds_entity *observed;
if (dds_entity_pin (ws->entities[0].handle, &observed) < 0)
{
/* can't be pinned => being deleted => will be removed from wait set soon enough
and go through delete_observer (which will trigger the condition variable) */
ddsrt_cond_wait (&ws->wait_cond, &ws->wait_lock);
}
else
{
/* entity will remain in existence */
ddsrt_mutex_unlock (&ws->wait_lock);
(void) dds_entity_observer_unregister (observed, ws, true);
ddsrt_mutex_lock (&ws->wait_lock);
assert (ws->nentities == 0 || ws->entities[0].entity != observed);
dds_entity_unpin (observed);
}
}
ddsrt_mutex_unlock (&ws->wait_lock);
}
static dds_return_t dds_waitset_delete (struct dds_entity *e)
{
/* deep in the process of deleting the entity, so this is the only thread */
dds_waitset *ws = (dds_waitset *) e;
ddsrt_mutex_destroy (&ws->wait_lock);
ddsrt_cond_destroy (&ws->wait_cond);
ddsrt_free (ws->entities);
return DDS_RETCODE_OK;
}
const struct dds_entity_deriver dds_entity_deriver_waitset = {
.interrupt = dds_waitset_interrupt,
.close = dds_waitset_close,
.delete = dds_waitset_delete,
.set_qos = dds_entity_deriver_dummy_set_qos,
.validate_status = dds_entity_deriver_dummy_validate_status
};
dds_entity_t dds_create_waitset (dds_entity_t participant)
dds_entity_t dds_create_waitset (dds_entity_t owner)
{
dds_entity_t hdl;
dds_participant *par;
dds_entity *e;
dds_return_t rc;
if ((rc = dds_participant_lock (participant, &par)) != DDS_RETCODE_OK)
/* If the owner is any ordinary (allowed) entity, the library is already initialised and calling
init here is cheap. If it is DDS_CYCLONEDDS_HANDLE, we may have to initialise the library, so
have to call it. If it is some bogus value and the library is not initialised yet ... so be
it. Naturally, this requires us to call delete on DDS_CYCLONEDDS_HANDLE afterward. */
if ((rc = dds_init ()) < 0)
return rc;
if ((rc = dds_entity_lock (owner, DDS_KIND_DONTCARE, &e)) != DDS_RETCODE_OK)
goto err_entity_lock;
switch (dds_entity_kind (e))
{
case DDS_KIND_CYCLONEDDS:
case DDS_KIND_DOMAIN:
case DDS_KIND_PARTICIPANT:
break;
default:
rc = DDS_RETCODE_ILLEGAL_OPERATION;
goto err_entity_kind;
}
dds_waitset *waitset = dds_alloc (sizeof (*waitset));
hdl = dds_entity_init (&waitset->m_entity, &par->m_entity, DDS_KIND_WAITSET, NULL, NULL, 0);
dds_entity_t hdl = dds_entity_init (&waitset->m_entity, e, DDS_KIND_WAITSET, NULL, NULL, 0);
ddsrt_mutex_init (&waitset->wait_lock);
ddsrt_cond_init (&waitset->wait_cond);
waitset->m_entity.m_iid = ddsi_iid_gen ();
dds_entity_register_child (&par->m_entity, &waitset->m_entity);
dds_entity_register_child (e, &waitset->m_entity);
waitset->nentities = 0;
waitset->ntriggered = 0;
waitset->entities = NULL;
dds_participant_unlock (par);
dds_entity_init_complete (&waitset->m_entity);
dds_entity_unlock (e);
dds_delete_impl_pinned (&dds_global.m_entity, DIS_EXPLICIT);
return hdl;
err_entity_kind:
dds_entity_unlock (e);
err_entity_lock:
dds_delete_impl_pinned (&dds_global.m_entity, DIS_EXPLICIT);
return rc;
}
dds_return_t dds_waitset_get_entities (dds_entity_t waitset, dds_entity_t *entities, size_t size)
{
dds_return_t ret;
dds_waitset *ws;
if ((ret = dds_waitset_lock (waitset, &ws)) != DDS_RETCODE_OK)
dds_entity *wsent;
if ((ret = dds_entity_pin (waitset, &wsent)) < 0)
return ret;
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;
}
}

View file

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

View file

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

View file

@ -51,34 +51,36 @@ static dds_return_t dds_writer_status_validate (uint32_t mask)
static void dds_writer_status_cb (void *ventity, const status_cb_data_t *data)
{
struct dds_entity * const entity = ventity;
dds_writer * const wr = ventity;
/* When data is NULL, it means that the writer is deleted. */
/* When data is NULL, it means that the DDSI reader is deleted. */
if (data == NULL)
{
/* Release the initial claim that was done during the create. This
* will indicate that further API deletion is now possible. */
dds_handle_unpin (&entity->m_hdllink);
ddsrt_mutex_lock (&wr->m_entity.m_mutex);
wr->m_wr = NULL;
ddsrt_cond_broadcast (&wr->m_entity.m_cond);
ddsrt_mutex_unlock (&wr->m_entity.m_mutex);
return;
}
struct dds_listener const * const lst = &entity->m_listener;
struct dds_listener const * const lst = &wr->m_entity.m_listener;
enum dds_status_id status_id = (enum dds_status_id) data->raw_status_id;
bool invoke = false;
void *vst = NULL;
int32_t *reset[2] = { NULL, NULL };
ddsrt_mutex_lock (&entity->m_observers_lock);
while (entity->m_cb_count > 0)
ddsrt_cond_wait (&entity->m_observers_cond, &entity->m_observers_lock);
entity->m_cb_count++;
/* FIXME: why wait if no listener is set? */
ddsrt_mutex_lock (&wr->m_entity.m_observers_lock);
while (wr->m_entity.m_cb_count > 0)
ddsrt_cond_wait (&wr->m_entity.m_observers_cond, &wr->m_entity.m_observers_lock);
/* Reset the status for possible Listener call.
* When a listener is not called, the status will be set (again). */
dds_entity_status_reset (entity, (status_mask_t) (1u << status_id));
dds_entity_status_reset (&wr->m_entity, (status_mask_t) (1u << status_id));
/* Update status metrics. */
dds_writer * const wr = (dds_writer *) entity;
switch (status_id)
{
case DDS_OFFERED_DEADLINE_MISSED_STATUS_ID: {
@ -136,23 +138,31 @@ static void dds_writer_status_cb (void *ventity, const status_cb_data_t *data)
assert (0);
}
if (invoke)
const uint32_t enabled = (ddsrt_atomic_ld32 (&wr->m_entity.m_status.m_status_and_mask) & ((1u << status_id) << SAM_ENABLED_SHIFT));
if (enabled == 0)
{
ddsrt_mutex_unlock (&entity->m_observers_lock);
dds_entity_invoke_listener(entity, status_id, vst);
ddsrt_mutex_lock (&entity->m_observers_lock);
/* Don't invoke listeners or set status flag if masked */
}
else if (invoke)
{
wr->m_entity.m_cb_pending_count++;
wr->m_entity.m_cb_count++;
ddsrt_mutex_unlock (&wr->m_entity.m_observers_lock);
dds_entity_invoke_listener (&wr->m_entity, status_id, vst);
ddsrt_mutex_lock (&wr->m_entity.m_observers_lock);
wr->m_entity.m_cb_count--;
wr->m_entity.m_cb_pending_count--;
*reset[0] = 0;
if (reset[1])
*reset[1] = 0;
}
else
{
dds_entity_status_set (entity, (status_mask_t) (1u << status_id));
dds_entity_status_set (&wr->m_entity, (status_mask_t) (1u << status_id));
}
entity->m_cb_count--;
ddsrt_cond_broadcast (&entity->m_observers_cond);
ddsrt_mutex_unlock (&entity->m_observers_lock);
ddsrt_cond_broadcast (&wr->m_entity.m_observers_cond);
ddsrt_mutex_unlock (&wr->m_entity.m_observers_lock);
}
static uint32_t get_bandwidth_limit (dds_transport_priority_qospolicy_t transport_priority)
@ -166,18 +176,32 @@ static uint32_t get_bandwidth_limit (dds_transport_priority_qospolicy_t transpor
#endif
}
static dds_return_t dds_writer_close (dds_entity *e) ddsrt_nonnull_all;
static void dds_writer_interrupt (dds_entity *e) ddsrt_nonnull_all;
static dds_return_t dds_writer_close (dds_entity *e)
static void dds_writer_interrupt (dds_entity *e)
{
dds_writer * const wr = (dds_writer *) e;
dds_return_t ret;
thread_state_awake (lookup_thread_state (), &e->m_domain->gv);
nn_xpack_send (wr->m_xp, false);
if ((ret = delete_writer (&e->m_domain->gv, &e->m_guid)) < 0)
ret = DDS_RETCODE_ERROR;
struct q_globals * const gv = &e->m_domain->gv;
thread_state_awake (lookup_thread_state (), gv);
unblock_throttled_writer (gv, &e->m_guid);
thread_state_asleep (lookup_thread_state ());
return ret;
}
static void dds_writer_close (dds_entity *e) ddsrt_nonnull_all;
static void dds_writer_close (dds_entity *e)
{
struct dds_writer * const wr = (struct dds_writer *) e;
struct q_globals * const gv = &e->m_domain->gv;
struct thread_state1 * const ts1 = lookup_thread_state ();
thread_state_awake (ts1, gv);
nn_xpack_send (wr->m_xp, false);
(void) delete_writer (gv, &e->m_guid);
thread_state_asleep (ts1);
ddsrt_mutex_lock (&e->m_mutex);
while (wr->m_wr != NULL)
ddsrt_cond_wait (&e->m_cond, &e->m_mutex);
ddsrt_mutex_unlock (&e->m_mutex);
}
static dds_return_t dds_writer_delete (dds_entity *e) ddsrt_nonnull_all;
@ -190,12 +214,7 @@ static dds_return_t dds_writer_delete (dds_entity *e)
thread_state_awake (lookup_thread_state (), &e->m_domain->gv);
nn_xpack_free (wr->m_xp);
thread_state_asleep (lookup_thread_state ());
if ((ret = dds_delete (wr->m_topic->m_entity.m_hdllink.hdl)) == DDS_RETCODE_OK)
{
ret = dds_delete_impl (e->m_parent->m_hdllink.hdl, true);
if (ret == DDS_RETCODE_BAD_PARAMETER)
ret = DDS_RETCODE_OK;
}
ret = dds_delete (wr->m_topic->m_entity.m_hdllink.hdl);
return ret;
}
@ -238,6 +257,7 @@ static struct whc *make_whc (struct dds_domain *dom, const dds_qos_t *qos)
}
const struct dds_entity_deriver dds_entity_deriver_writer = {
.interrupt = dds_writer_interrupt,
.close = dds_writer_close,
.delete = dds_writer_delete,
.set_qos = dds_writer_qos_set,
@ -251,6 +271,7 @@ dds_entity_t dds_create_writer (dds_entity_t participant_or_publisher, dds_entit
dds_writer *wr;
dds_entity_t writer;
dds_publisher *pub = NULL;
dds_participant *pp;
dds_topic *tp;
dds_entity_t publisher;
@ -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;
}

View file

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

View file

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

View file

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

View file

@ -0,0 +1,142 @@
/*
* Copyright(c) 2019 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include <stdlib.h>
#include "dds/dds.h"
#include "CUnit/Test.h"
#include "config_env.h"
#include "dds/version.h"
#include "dds/ddsrt/environ.h"
CU_Test(ddsc_domain, get_domainid)
{
dds_entity_t pp, d, x;
dds_return_t rc;
uint32_t did;
pp = dds_create_participant (0, NULL, NULL);
CU_ASSERT_FATAL (pp > 0);
d = dds_get_parent (pp);
CU_ASSERT_FATAL (d > 0);
x = dds_get_parent (d);
CU_ASSERT_FATAL (x == DDS_CYCLONEDDS_HANDLE);
x = dds_get_parent (x);
CU_ASSERT_FATAL (x == 0);
rc = dds_get_domainid (pp, &did);
CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
CU_ASSERT_FATAL (did == 0);
rc = dds_get_domainid (d, &did);
CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
CU_ASSERT_FATAL (did == 0);
rc = dds_get_domainid (DDS_CYCLONEDDS_HANDLE, &did);
CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
CU_ASSERT_FATAL (did == DDS_DOMAIN_DEFAULT);
rc = dds_delete (pp);
CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
}
CU_Test(ddsc_domain, delete_domain0)
{
dds_entity_t pp[3], d[3];
dds_return_t rc;
uint32_t did;
for (dds_domainid_t i = 0; i < (dds_domainid_t) (sizeof (pp) / sizeof (pp[0])); i++)
{
pp[i] = dds_create_participant (0, NULL, NULL);
CU_ASSERT_FATAL (pp[i] > 0);
d[i] = dds_get_parent (pp[i]);
CU_ASSERT_FATAL (d[i] > 0);
if (i > 0)
CU_ASSERT_FATAL (d[i] == d[i-1]);
}
rc = dds_delete (pp[0]);
CU_ASSERT_FATAL (rc == 0);
rc = dds_get_domainid (pp[0], &did);
CU_ASSERT_FATAL (rc == DDS_RETCODE_BAD_PARAMETER);
for (size_t i = 1; i < sizeof (pp) / sizeof (pp[0]); i++)
{
rc = dds_get_domainid (pp[i], &did);
CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
CU_ASSERT_FATAL (did == 0);
}
rc = dds_delete (d[1]);
CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
/* Deleting the domain should delete all participants in it as well,
and as there is only a single domain in this test, that should
de-initialize the library.
A non-initialized library returns PRECONDITION_NOT_MET; an
initialized one given an invalid handle returns BAD_PARAMETER,
so we can distinguish the two cases. */
rc = dds_get_domainid (pp[1], &did);
CU_ASSERT_FATAL (rc == DDS_RETCODE_PRECONDITION_NOT_MET);
}
CU_Test(ddsc_domain, delete_domainM)
{
dds_entity_t pp[3], d[3], x;
dds_return_t rc;
uint32_t did;
for (dds_domainid_t i = 0; i < (dds_domainid_t) (sizeof (pp) / sizeof (pp[0])); i++)
{
pp[i] = dds_create_participant (i, NULL, NULL);
CU_ASSERT_FATAL (pp[i] > 0);
d[i] = dds_get_parent (pp[i]);
CU_ASSERT_FATAL (d[i] > 0);
for (dds_domainid_t j = 0; j < i; j++)
CU_ASSERT_FATAL (d[i] != d[j]);
}
/* deleting participant 0 should tear down domain 0, but nothing else */
rc = dds_delete (pp[0]);
CU_ASSERT_FATAL (rc == 0);
rc = dds_get_domainid (pp[0], &did);
CU_ASSERT_FATAL (rc == DDS_RETCODE_BAD_PARAMETER);
rc = dds_get_domainid (d[0], &did);
CU_ASSERT_FATAL (rc == DDS_RETCODE_BAD_PARAMETER);
/* deleting domain should delete participant 1, but leave domain 2 alone */
rc = dds_delete (d[1]);
CU_ASSERT_FATAL (rc == 0);
rc = dds_get_domainid (pp[1], &did);
CU_ASSERT_FATAL (rc == DDS_RETCODE_BAD_PARAMETER);
x = dds_get_parent (pp[2]);
CU_ASSERT_FATAL (x == d[2]);
/* after deleting participant 2, everything should be gone */
rc = dds_delete (pp[2]);
CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
rc = dds_get_domainid (pp[1], &did);
CU_ASSERT_FATAL (rc == DDS_RETCODE_PRECONDITION_NOT_MET);
}
CU_Test(ddsc_domain, delete_cyclonedds)
{
dds_entity_t pp[3], d[3];
dds_return_t rc;
uint32_t did;
for (dds_domainid_t i = 0; i < (dds_domainid_t) (sizeof (pp) / sizeof (pp[0])); i++)
{
pp[i] = dds_create_participant (i, NULL, NULL);
CU_ASSERT_FATAL (pp[i] > 0);
d[i] = dds_get_parent (pp[i]);
CU_ASSERT_FATAL (d[i] > 0);
for (dds_domainid_t j = 0; j < i; j++)
CU_ASSERT_FATAL (d[i] != d[j]);
}
/* deleting participant 0 should tear down domain 0, but nothing else */
rc = dds_delete (DDS_CYCLONEDDS_HANDLE);
CU_ASSERT_FATAL (rc == 0);
rc = dds_get_domainid (pp[0], &did);
CU_ASSERT_FATAL (rc == DDS_RETCODE_PRECONDITION_NOT_MET);
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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