Merge branch 'master' into merge
Signed-off-by: Martin Bremmer <martin.bremmer@adlinktech.com>
This commit is contained in:
commit
919850232c
128 changed files with 6936 additions and 2075 deletions
|
@ -50,6 +50,7 @@ PREPEND(hdrs_public_ddsc "$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include/dd
|
|||
ddsc/dds_public_qos.h
|
||||
ddsc/dds_public_qosdefs.h
|
||||
ddsc/dds_public_status.h
|
||||
ddsc/dds_rhc.h
|
||||
)
|
||||
|
||||
PREPEND(hdrs_private_ddsc "${CMAKE_CURRENT_LIST_DIR}/src"
|
||||
|
@ -67,7 +68,6 @@ PREPEND(hdrs_private_ddsc "${CMAKE_CURRENT_LIST_DIR}/src"
|
|||
dds__readcond.h
|
||||
dds__guardcond.h
|
||||
dds__reader.h
|
||||
dds__rhc.h
|
||||
dds__rhc_default.h
|
||||
dds__stream.h
|
||||
dds__subscriber.h
|
||||
|
|
|
@ -49,19 +49,9 @@ typedef int32_t dds_entity_t;
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct dds_rhc;
|
||||
struct ddsi_serdata;
|
||||
|
||||
/**
|
||||
* @brief Returns the default domain identifier.
|
||||
*
|
||||
* The default domain identifier can be configured in the configuration file
|
||||
* or be set through an evironment variable ({DDSC_PROJECT_NAME_NOSPACE_CAPS}_DOMAIN).
|
||||
*
|
||||
* @returns Default domain identifier
|
||||
*/
|
||||
DDS_EXPORT dds_domainid_t dds_domain_default (void);
|
||||
|
||||
|
||||
#define DDS_MIN_PSEUDO_HANDLE ((dds_entity_t) 0x7fff0000)
|
||||
|
||||
/* @defgroup builtintopic_constants Convenience constants for referring to builtin topics
|
||||
|
@ -77,6 +67,9 @@ DDS_EXPORT dds_domainid_t dds_domain_default (void);
|
|||
#define DDS_BUILTIN_TOPIC_DCPSSUBSCRIPTION ((dds_entity_t) (DDS_MIN_PSEUDO_HANDLE + 4))
|
||||
/** @}*/
|
||||
|
||||
/** Special handle representing the entity corresponding to the CycloneDDS library itself */
|
||||
#define DDS_CYCLONEDDS_HANDLE ((dds_entity_t) (DDS_MIN_PSEUDO_HANDLE + 256))
|
||||
|
||||
/** @name Communication Status definitions
|
||||
@{**/
|
||||
typedef enum dds_status_id {
|
||||
|
@ -733,7 +726,7 @@ dds_set_listener(dds_entity_t entity, const dds_listener_t * listener);
|
|||
* If no configuration file exists, the default domain is configured as 0.
|
||||
*
|
||||
*
|
||||
* @param[in] domain The domain in which to create the participant (can be DDS_DOMAIN_DEFAULT). Valid values for domain id are between 0 and 230. DDS_DOMAIN_DEFAULT is for using the domain in the configuration.
|
||||
* @param[in] domain The domain in which to create the participant (can be DDS_DOMAIN_DEFAULT). DDS_DOMAIN_DEFAULT is for using the domain in the configuration.
|
||||
* @param[in] qos The QoS to set on the new participant (can be NULL).
|
||||
* @param[in] listener Any listener functions associated with the new participant (can be NULL).
|
||||
|
||||
|
@ -750,6 +743,33 @@ dds_create_participant(
|
|||
const dds_qos_t *qos,
|
||||
const dds_listener_t *listener);
|
||||
|
||||
/**
|
||||
* @brief Creates a domain with a given configuration
|
||||
*
|
||||
* To explicitly create a domain based on a configuration passed as a string.
|
||||
* Normally, the domain is created implicitly on the first call to
|
||||
* dds_create_particiant based on the configuration specified throught
|
||||
* the environment. This function allows to by-pass this behaviour.
|
||||
*
|
||||
*
|
||||
* @param[in] domain The domain to be created. DEFAULT_DOMAIN is not allowed.
|
||||
* @param[in] config A configuration string containing file names and/or XML fragments representing the configuration.
|
||||
*
|
||||
* @returns A return code
|
||||
*
|
||||
* @retval DDS_RETCODE_OK
|
||||
* The domain with the domain identifier has been created from
|
||||
* given configuration string.
|
||||
* @retval DDS_RETCODE_BAD_PARAMETER
|
||||
* Illegal value for domain id or the configfile parameter is NULL.
|
||||
* @retval DDS_PRECONDITION_NOT_MET
|
||||
* The domain already existed and cannot be created again.
|
||||
* @retval DDS_RETCODE_ERROR
|
||||
* An internal error has occurred.
|
||||
*/
|
||||
DDS_EXPORT dds_return_t
|
||||
dds_create_domain(const dds_domainid_t domain, const char *config);
|
||||
|
||||
/**
|
||||
* @brief Get entity parent.
|
||||
*
|
||||
|
@ -871,7 +891,8 @@ dds_get_children(dds_entity_t entity, dds_entity_t *children, size_t size);
|
|||
* DataReaders), etc are also attached to that domain.
|
||||
*
|
||||
* This function will return the original domain ID when called on
|
||||
* any of the entities within that hierarchy.
|
||||
* any of the entities within that hierarchy. For entities not associated
|
||||
* with a domain, the id is set to DDS_DOMAIN_DEFAULT.
|
||||
*
|
||||
* @param[in] entity Entity from which to get its children.
|
||||
* @param[out] id Pointer to put the domain ID in.
|
||||
|
@ -1202,6 +1223,34 @@ dds_create_reader(
|
|||
const dds_qos_t *qos,
|
||||
const dds_listener_t *listener);
|
||||
|
||||
/**
|
||||
* @brief Creates a new instance of a DDS reader with a custom history cache.
|
||||
*
|
||||
* This implicit subscriber will be deleted automatically when the created reader
|
||||
* is deleted.
|
||||
*
|
||||
* @param[in] participant_or_subscriber The participant or subscriber on which the reader is being created.
|
||||
* @param[in] topic The topic to read.
|
||||
* @param[in] qos The QoS to set on the new reader (can be NULL).
|
||||
* @param[in] listener Any listener functions associated with the new reader (can be NULL).
|
||||
* @param[in] rhc Reader history cache to use, reader becomes the owner
|
||||
*
|
||||
* @returns A valid reader handle or an error code.
|
||||
*
|
||||
* @retval >0
|
||||
* A valid reader handle.
|
||||
* @retval DDS_RETCODE_ERROR
|
||||
* An internal error occurred.
|
||||
*/
|
||||
/* TODO: Complete list of error codes */
|
||||
DDS_EXPORT dds_entity_t
|
||||
dds_create_reader_rhc(
|
||||
dds_entity_t participant_or_subscriber,
|
||||
dds_entity_t topic,
|
||||
const dds_qos_t *qos,
|
||||
const dds_listener_t *listener,
|
||||
struct dds_rhc *rhc);
|
||||
|
||||
/**
|
||||
* @brief Wait until reader receives all historic data
|
||||
*
|
||||
|
|
|
@ -108,7 +108,9 @@ typedef enum dds_entity_kind
|
|||
DDS_KIND_COND_READ,
|
||||
DDS_KIND_COND_QUERY,
|
||||
DDS_KIND_COND_GUARD,
|
||||
DDS_KIND_WAITSET
|
||||
DDS_KIND_WAITSET,
|
||||
DDS_KIND_DOMAIN,
|
||||
DDS_KIND_CYCLONEDDS
|
||||
} dds_entity_kind_t;
|
||||
|
||||
/* Handles are opaque pointers to implementation types */
|
||||
|
|
|
@ -13,8 +13,7 @@
|
|||
#define _DDS_RHC_H_
|
||||
|
||||
#include "dds/ddsrt/static_assert.h"
|
||||
#include "dds/ddsi/q_rhc.h"
|
||||
#include "dds__types.h" /* for dds_readcond */
|
||||
#include "dds/ddsi/ddsi_rhc.h"
|
||||
|
||||
#define NO_STATE_MASK_SET (DDS_ANY_STATE + 1)
|
||||
|
||||
|
@ -23,42 +22,50 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
struct dds_rhc;
|
||||
struct dds_readcond;
|
||||
struct dds_reader;
|
||||
struct ddsi_tkmap;
|
||||
|
||||
typedef dds_return_t (*dds_rhc_associate_t) (struct dds_rhc *rhc, struct dds_reader *reader, const struct ddsi_sertopic *topic, struct ddsi_tkmap *tkmap);
|
||||
typedef int (*dds_rhc_read_t) (struct dds_rhc *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, struct dds_readcond *cond);
|
||||
typedef int (*dds_rhc_take_t) (struct dds_rhc *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, struct dds_readcond *cond);
|
||||
typedef int (*dds_rhc_takecdr_t) (struct dds_rhc *rhc, bool lock, struct ddsi_serdata **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t sample_states, uint32_t view_states, uint32_t instance_states, dds_instance_handle_t handle);
|
||||
|
||||
typedef bool (*dds_rhc_add_readcondition_t) (struct dds_readcond *cond);
|
||||
typedef void (*dds_rhc_remove_readcondition_t) (struct dds_readcond *cond);
|
||||
typedef bool (*dds_rhc_add_readcondition_t) (struct dds_rhc *rhc, struct dds_readcond *cond);
|
||||
typedef void (*dds_rhc_remove_readcondition_t) (struct dds_rhc *rhc, struct dds_readcond *cond);
|
||||
|
||||
typedef uint32_t (*dds_rhc_lock_samples_t) (struct dds_rhc *rhc);
|
||||
|
||||
struct dds_rhc_ops {
|
||||
/* A copy of DDSI rhc ops comes first so we can use either interface without
|
||||
additional indirections */
|
||||
struct rhc_ops rhc_ops;
|
||||
struct ddsi_rhc_ops rhc_ops;
|
||||
dds_rhc_read_t read;
|
||||
dds_rhc_take_t take;
|
||||
dds_rhc_takecdr_t takecdr;
|
||||
dds_rhc_add_readcondition_t add_readcondition;
|
||||
dds_rhc_remove_readcondition_t remove_readcondition;
|
||||
dds_rhc_lock_samples_t lock_samples;
|
||||
dds_rhc_associate_t associate;
|
||||
};
|
||||
|
||||
struct dds_rhc {
|
||||
union {
|
||||
const struct dds_rhc_ops *ops;
|
||||
struct rhc rhc;
|
||||
struct ddsi_rhc rhc;
|
||||
} common;
|
||||
};
|
||||
|
||||
DDSRT_STATIC_ASSERT (offsetof (struct dds_rhc, common.ops) == offsetof (struct rhc, ops));
|
||||
DDSRT_STATIC_ASSERT (offsetof (struct dds_rhc, common.ops) == offsetof (struct ddsi_rhc, ops));
|
||||
|
||||
DDS_EXPORT inline bool dds_rhc_store (struct dds_rhc * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info, struct ddsi_serdata * __restrict sample, struct ddsi_tkmap_instance * __restrict tk) {
|
||||
return rhc->common.ops->rhc_ops.store (&rhc->common.rhc, pwr_info, sample, tk);
|
||||
DDS_EXPORT inline dds_return_t dds_rhc_associate (struct dds_rhc *rhc, struct dds_reader *reader, const struct ddsi_sertopic *topic, struct ddsi_tkmap *tkmap) {
|
||||
return rhc->common.ops->associate (rhc, reader, topic, tkmap);
|
||||
}
|
||||
DDS_EXPORT inline void dds_rhc_unregister_wr (struct dds_rhc * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info) {
|
||||
rhc->common.ops->rhc_ops.unregister_wr (&rhc->common.rhc, pwr_info);
|
||||
DDS_EXPORT inline bool dds_rhc_store (struct dds_rhc * __restrict rhc, const struct ddsi_writer_info * __restrict wrinfo, struct ddsi_serdata * __restrict sample, struct ddsi_tkmap_instance * __restrict tk) {
|
||||
return rhc->common.ops->rhc_ops.store (&rhc->common.rhc, wrinfo, sample, tk);
|
||||
}
|
||||
DDS_EXPORT inline void dds_rhc_unregister_wr (struct dds_rhc * __restrict rhc, const struct ddsi_writer_info * __restrict wrinfo) {
|
||||
rhc->common.ops->rhc_ops.unregister_wr (&rhc->common.rhc, wrinfo);
|
||||
}
|
||||
DDS_EXPORT inline void dds_rhc_relinquish_ownership (struct dds_rhc * __restrict rhc, const uint64_t wr_iid) {
|
||||
rhc->common.ops->rhc_ops.relinquish_ownership (&rhc->common.rhc, wr_iid);
|
||||
|
@ -78,16 +85,18 @@ DDS_EXPORT inline int dds_rhc_take (struct dds_rhc *rhc, bool lock, void **value
|
|||
DDS_EXPORT inline int dds_rhc_takecdr (struct dds_rhc *rhc, bool lock, struct ddsi_serdata **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t sample_states, uint32_t view_states, uint32_t instance_states, dds_instance_handle_t handle) {
|
||||
return rhc->common.ops->takecdr (rhc, lock, values, info_seq, max_samples, sample_states, view_states, instance_states, handle);
|
||||
}
|
||||
DDS_EXPORT inline bool dds_rhc_add_readcondition (struct dds_readcond *cond) {
|
||||
return cond->m_rhc->common.ops->add_readcondition (cond);
|
||||
DDS_EXPORT inline bool dds_rhc_add_readcondition (struct dds_rhc *rhc, struct dds_readcond *cond) {
|
||||
return rhc->common.ops->add_readcondition (rhc, cond);
|
||||
}
|
||||
DDS_EXPORT inline void dds_rhc_remove_readcondition (struct dds_readcond *cond) {
|
||||
cond->m_rhc->common.ops->remove_readcondition (cond);
|
||||
DDS_EXPORT inline void dds_rhc_remove_readcondition (struct dds_rhc *rhc, struct dds_readcond *cond) {
|
||||
rhc->common.ops->remove_readcondition (rhc, cond);
|
||||
}
|
||||
DDS_EXPORT inline uint32_t dds_rhc_lock_samples (struct dds_rhc *rhc) {
|
||||
return rhc->common.ops->lock_samples (rhc);
|
||||
}
|
||||
|
||||
DDS_EXPORT void dds_reader_data_available_cb (struct dds_reader *rd);
|
||||
|
||||
#if defined (__cplusplus)
|
||||
}
|
||||
#endif
|
|
@ -18,8 +18,7 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
DDS_EXPORT dds_return_t dds_domain_create (dds_domain **domain_out, dds_domainid_t id);
|
||||
DDS_EXPORT void dds_domain_free (dds_domain *domain);
|
||||
DDS_EXPORT dds_return_t dds_domain_create_internal (dds_domain **domain_out, dds_domainid_t id, bool use_existing, const char *config) ddsrt_nonnull((1,4));
|
||||
DDS_EXPORT dds_domain *dds_domain_find_locked (dds_domainid_t id);
|
||||
|
||||
#if defined (__cplusplus)
|
||||
|
|
|
@ -28,6 +28,8 @@ dds_entity_init(
|
|||
const dds_listener_t *listener,
|
||||
status_mask_t mask);
|
||||
|
||||
DDS_EXPORT void dds_entity_init_complete (dds_entity *entity);
|
||||
|
||||
DDS_EXPORT void
|
||||
dds_entity_register_child (
|
||||
dds_entity *parent,
|
||||
|
@ -46,7 +48,6 @@ dds_entity_add_ref_locked(dds_entity *e);
|
|||
*x = (type_ *) e; \
|
||||
return DDS_RETCODE_OK; \
|
||||
} \
|
||||
\
|
||||
qualifier_ void type_##_unlock (type_ *x) \
|
||||
{ \
|
||||
dds_entity_unlock (&x->m_entity); \
|
||||
|
@ -78,6 +79,18 @@ DDS_EXPORT void dds_entity_status_signal (dds_entity *e, uint32_t status);
|
|||
|
||||
DDS_EXPORT void dds_entity_invoke_listener (const dds_entity *entity, enum dds_status_id which, const void *vst);
|
||||
|
||||
DDS_EXPORT dds_participant *dds_entity_participant (dds_entity *e);
|
||||
DDS_EXPORT void dds_entity_final_deinit_before_free (dds_entity *e);
|
||||
DDS_EXPORT bool dds_entity_in_scope (const dds_entity *e, const dds_entity *root);
|
||||
|
||||
enum delete_impl_state {
|
||||
DIS_EXPLICIT, /* explicit delete on this entity */
|
||||
DIS_FROM_PARENT, /* called because the parent is being deleted */
|
||||
DIS_IMPLICIT /* called from child; delete if implicit w/o children */
|
||||
};
|
||||
|
||||
DDS_EXPORT dds_return_t dds_delete_impl_pinned (dds_entity *e, enum delete_impl_state delstate);
|
||||
|
||||
DDS_EXPORT dds_return_t
|
||||
dds_entity_pin (
|
||||
dds_entity_t hdl,
|
||||
|
@ -98,23 +111,16 @@ dds_entity_unlock(dds_entity *e);
|
|||
DDS_EXPORT dds_return_t
|
||||
dds_entity_observer_register(
|
||||
dds_entity *observed,
|
||||
dds_entity *observer,
|
||||
dds_entity_callback cb,
|
||||
dds_entity_delete_callback delete_cb);
|
||||
dds_waitset *observer,
|
||||
dds_entity_callback_t cb,
|
||||
dds_entity_attach_callback_t attach_cb, void *attach_arg,
|
||||
dds_entity_delete_callback_t delete_cb);
|
||||
|
||||
DDS_EXPORT dds_return_t
|
||||
dds_entity_observer_unregister(
|
||||
dds_entity *observed,
|
||||
dds_entity *observer);
|
||||
|
||||
DDS_EXPORT dds_return_t
|
||||
dds_delete_impl(
|
||||
dds_entity_t entity,
|
||||
bool keep_if_explicit);
|
||||
|
||||
DDS_EXPORT dds_domain *
|
||||
dds__entity_domain(
|
||||
dds_entity* e);
|
||||
dds_waitset *observer,
|
||||
bool invoke_delete_cb);
|
||||
|
||||
DDS_EXPORT dds_return_t
|
||||
dds_generic_unimplemented_operation_manykinds(
|
||||
|
|
|
@ -69,6 +69,13 @@ typedef int32_t dds_handle_t;
|
|||
* This handlelink is invalid after the related handle is deleted and should
|
||||
* never be used afterwards.
|
||||
*/
|
||||
|
||||
/* Closing & closed can be combined, but having two gives a means for enforcing
|
||||
that close() be called first, then close_wait(), and then delete(). */
|
||||
#define HDL_FLAG_CLOSING (0x80000000u)
|
||||
#define HDL_FLAG_CLOSED (0x40000000u)
|
||||
#define HDL_FLAG_PENDING (0x20000000u)
|
||||
|
||||
struct dds_handle_link {
|
||||
dds_handle_t hdl;
|
||||
ddsrt_atomic_uint32_t cnt_flags;
|
||||
|
@ -112,6 +119,15 @@ dds_handle_create(
|
|||
struct dds_handle_link *link);
|
||||
|
||||
|
||||
/*
|
||||
* Register a specific handle.
|
||||
*/
|
||||
DDS_EXPORT dds_return_t
|
||||
dds_handle_register_special (
|
||||
struct dds_handle_link *link, dds_handle_t handle);
|
||||
|
||||
DDS_EXPORT void dds_handle_unpend (struct dds_handle_link *link);
|
||||
|
||||
/*
|
||||
* This will close the handle. All information remains, only new claims will
|
||||
* fail.
|
||||
|
@ -119,10 +135,9 @@ dds_handle_create(
|
|||
* This is a noop on an already closed handle.
|
||||
*/
|
||||
DDS_EXPORT void
|
||||
dds_handle_close(
|
||||
dds_handle_close_wait (
|
||||
struct dds_handle_link *link);
|
||||
|
||||
|
||||
/*
|
||||
* This will remove the handle related information from the server administration
|
||||
* to free up space.
|
||||
|
@ -134,8 +149,7 @@ dds_handle_close(
|
|||
*/
|
||||
DDS_EXPORT int32_t
|
||||
dds_handle_delete(
|
||||
struct dds_handle_link *link,
|
||||
dds_time_t timeout);
|
||||
struct dds_handle_link *link);
|
||||
|
||||
|
||||
/*
|
||||
|
@ -149,6 +163,11 @@ dds_handle_pin(
|
|||
dds_handle_t hdl,
|
||||
struct dds_handle_link **entity);
|
||||
|
||||
DDS_EXPORT int32_t
|
||||
dds_handle_pin_and_ref(
|
||||
dds_handle_t hdl,
|
||||
struct dds_handle_link **entity);
|
||||
|
||||
|
||||
DDS_EXPORT void
|
||||
dds_handle_repin(
|
||||
|
@ -172,14 +191,15 @@ dds_handle_unpin(
|
|||
* break of your process and release the handle, making the deletion
|
||||
* possible.
|
||||
*/
|
||||
DDS_EXPORT bool
|
||||
dds_handle_is_closed(
|
||||
struct dds_handle_link *link);
|
||||
|
||||
|
||||
DDS_EXPORT void dds_handle_add_ref (struct dds_handle_link *link);
|
||||
DDS_EXPORT bool dds_handle_drop_ref (struct dds_handle_link *link);
|
||||
|
||||
DDS_EXPORT inline bool dds_handle_is_closed (struct dds_handle_link *link) {
|
||||
return (ddsrt_atomic_ld32 (&link->cnt_flags) & (HDL_FLAG_CLOSED | HDL_FLAG_CLOSING)) != 0;
|
||||
}
|
||||
|
||||
#if defined (__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -19,27 +19,15 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
/**
|
||||
*Description : Initialization function, called from main. This operation
|
||||
*initializes all the required DDS resources,
|
||||
*handles configuration of domainid based on the input passed, parses and
|
||||
*configures middleware from a xml file and initializes required resources.
|
||||
*Description : Initializes the library and constructs the global
|
||||
*pseudo-entity identified by DDS_CYCLONEDDS_HANDLE with one reference
|
||||
*that must (eventually) be released by calling dds_delete on that handle.
|
||||
*
|
||||
*Arguments :
|
||||
*-# Returns 0 on success or a non-zero error status
|
||||
**/
|
||||
dds_return_t dds_init (void);
|
||||
|
||||
/* Finalization function, called from main */
|
||||
|
||||
/**
|
||||
*Description : Finalization function, called from main. This operation
|
||||
*releases all the resources used by DDS.
|
||||
*
|
||||
*Arguments :
|
||||
*-# None
|
||||
**/
|
||||
void dds_fini (void);
|
||||
|
||||
#if defined (__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -23,8 +23,6 @@ struct status_cb_data;
|
|||
|
||||
void dds_reader_status_cb (void *entity, const struct status_cb_data * data);
|
||||
|
||||
void dds_reader_data_available_cb (struct dds_reader *entity);
|
||||
|
||||
/*
|
||||
dds_reader_lock_samples: Returns number of samples in read cache and locks the
|
||||
reader cache to make sure that the samples content doesn't change.
|
||||
|
|
|
@ -22,7 +22,7 @@ extern "C" {
|
|||
|
||||
struct ddsi_serdata_builtintopic {
|
||||
struct ddsi_serdata c;
|
||||
nn_guid_t key;
|
||||
ddsi_guid_t key;
|
||||
dds_instance_handle_t pphandle;
|
||||
dds_qos_t xqos;
|
||||
};
|
||||
|
|
|
@ -60,6 +60,10 @@ void dds_stream_extract_keyhash (dds_istream_t * __restrict is, dds_keyhash_t *
|
|||
|
||||
void dds_stream_read_key (dds_istream_t * __restrict is, char * __restrict sample, const struct ddsi_sertopic_default * __restrict topic);
|
||||
|
||||
size_t dds_stream_print_key (dds_istream_t * __restrict is, const struct ddsi_sertopic_default * __restrict topic, char * __restrict buf, size_t size);
|
||||
|
||||
size_t dds_stream_print_sample (dds_istream_t * __restrict is, const struct ddsi_sertopic_default * __restrict topic, char * __restrict buf, size_t size);
|
||||
|
||||
/* For marshalling op code handling */
|
||||
|
||||
#define DDS_OP_MASK 0xff000000
|
||||
|
|
|
@ -39,7 +39,7 @@ struct dds_guardcond;
|
|||
struct dds_statuscond;
|
||||
|
||||
struct ddsi_sertopic;
|
||||
struct rhc;
|
||||
struct ddsi_rhc;
|
||||
|
||||
typedef uint16_t status_mask_t;
|
||||
typedef ddsrt_atomic_uint32_t status_and_enabled_t;
|
||||
|
@ -90,47 +90,32 @@ struct dds_listener {
|
|||
|
||||
/* Entity flag values */
|
||||
|
||||
#define DDS_ENTITY_ENABLED 0x0001u
|
||||
#define DDS_ENTITY_IMPLICIT 0x0002u
|
||||
|
||||
typedef struct dds_domain {
|
||||
/* FIXME: protected by dds_global.lock -- for now */
|
||||
ddsrt_avl_node_t m_node;
|
||||
dds_domainid_t m_id;
|
||||
ddsrt_avl_tree_t m_topics;
|
||||
ddsrt_avl_tree_t m_ppants;
|
||||
uint32_t m_refc;
|
||||
struct cfgst *cfgst;
|
||||
|
||||
struct ddsi_sertopic *builtin_participant_topic;
|
||||
struct ddsi_sertopic *builtin_reader_topic;
|
||||
struct ddsi_sertopic *builtin_writer_topic;
|
||||
|
||||
struct local_orphan_writer *builtintopic_writer_participant;
|
||||
struct local_orphan_writer *builtintopic_writer_publications;
|
||||
struct local_orphan_writer *builtintopic_writer_subscriptions;
|
||||
|
||||
struct ddsi_builtin_topic_interface btif;
|
||||
struct q_globals gv;
|
||||
} dds_domain;
|
||||
#define DDS_ENTITY_ENABLED ((uint32_t) 0x1) /* DDS "enabled" state */
|
||||
#define DDS_ENTITY_IMPLICIT ((uint32_t) 0x2) /* implicit ones get deleted when the last child is deleted */
|
||||
|
||||
struct dds_domain;
|
||||
struct dds_entity;
|
||||
|
||||
typedef struct dds_entity_deriver {
|
||||
/* Close can be used to terminate (blocking) actions on a entity before actually deleting it. */
|
||||
dds_return_t (*close)(struct dds_entity *e) ddsrt_nonnull_all;
|
||||
/* Pending close can be used to terminate (blocking) actions on a entity before actually deleting it. */
|
||||
void (*interrupt) (struct dds_entity *e) ddsrt_nonnull_all;
|
||||
/* Close can be used to do ... */
|
||||
void (*close) (struct dds_entity *e) ddsrt_nonnull_all;
|
||||
/* Delete is used to actually free the entity. */
|
||||
dds_return_t (*delete)(struct dds_entity *e) ddsrt_nonnull_all;
|
||||
dds_return_t (*set_qos)(struct dds_entity *e, const dds_qos_t *qos, bool enabled) ddsrt_nonnull_all;
|
||||
dds_return_t (*validate_status)(uint32_t mask);
|
||||
dds_return_t (*delete) (struct dds_entity *e) ddsrt_nonnull_all;
|
||||
dds_return_t (*set_qos) (struct dds_entity *e, const dds_qos_t *qos, bool enabled) ddsrt_nonnull_all;
|
||||
dds_return_t (*validate_status) (uint32_t mask);
|
||||
} dds_entity_deriver;
|
||||
|
||||
typedef void (*dds_entity_callback)(struct dds_entity *observer, dds_entity_t observed, uint32_t status);
|
||||
typedef void (*dds_entity_delete_callback)(struct dds_entity *observer, dds_entity_t observed);
|
||||
struct dds_waitset;
|
||||
typedef void (*dds_entity_callback_t) (struct dds_waitset *observer, dds_entity_t observed, uint32_t status);
|
||||
typedef bool (*dds_entity_attach_callback_t) (struct dds_waitset *observer, struct dds_entity *observed, void *attach_arg);
|
||||
typedef void (*dds_entity_delete_callback_t) (struct dds_waitset *observer, dds_entity_t observed);
|
||||
|
||||
typedef struct dds_entity_observer {
|
||||
dds_entity_callback m_cb;
|
||||
dds_entity_delete_callback m_delete_cb;
|
||||
struct dds_entity *m_observer;
|
||||
dds_entity_callback_t m_cb;
|
||||
dds_entity_delete_callback_t m_delete_cb;
|
||||
struct dds_waitset *m_observer;
|
||||
struct dds_entity_observer *m_next;
|
||||
} dds_entity_observer;
|
||||
|
||||
|
@ -141,10 +126,9 @@ typedef struct dds_entity {
|
|||
struct dds_entity *m_parent; /* constant */
|
||||
ddsrt_avl_node_t m_avlnode_child; /* [m_mutex of m_parent] */
|
||||
ddsrt_avl_tree_t m_children; /* [m_mutex] tree on m_iid using m_avlnode_child */
|
||||
struct dds_entity *m_participant; /* constant */
|
||||
struct dds_domain *m_domain; /* constant */
|
||||
dds_qos_t *m_qos; /* [m_mutex] */
|
||||
nn_guid_t m_guid; /* unique (if not 0) and constant; FIXME: set during creation, but possibly after becoming visible */
|
||||
ddsi_guid_t m_guid; /* unique (if not 0) and constant; FIXME: set during creation, but possibly after becoming visible */
|
||||
dds_instance_handle_t m_iid; /* unique for all time, constant; FIXME: like GUID */
|
||||
uint32_t m_flags; /* [m_mutex] */
|
||||
|
||||
|
@ -154,6 +138,7 @@ typedef struct dds_entity {
|
|||
(no hierarchical relationship there)
|
||||
- locking topic::m_mutex while holding {reader,writer}::m_mutex
|
||||
- locking observers_lock while holding m_mutex
|
||||
- locking waitset::wait_lock
|
||||
*/
|
||||
ddsrt_mutex_t m_mutex;
|
||||
ddsrt_cond_t m_cond;
|
||||
|
@ -167,6 +152,7 @@ typedef struct dds_entity {
|
|||
ddsrt_cond_t m_observers_cond;
|
||||
dds_listener_t m_listener; /* [m_observers_lock] */
|
||||
uint32_t m_cb_count; /* [m_observers_lock] */
|
||||
uint32_t m_cb_pending_count; /* [m_observers_lock] */
|
||||
dds_entity_observer *m_observers; /* [m_observers_lock] */
|
||||
} dds_entity;
|
||||
|
||||
|
@ -182,16 +168,21 @@ extern const struct dds_entity_deriver dds_entity_deriver_publisher;
|
|||
extern const struct dds_entity_deriver dds_entity_deriver_readcondition;
|
||||
extern const struct dds_entity_deriver dds_entity_deriver_guardcondition;
|
||||
extern const struct dds_entity_deriver dds_entity_deriver_waitset;
|
||||
extern const struct dds_entity_deriver dds_entity_deriver_domain;
|
||||
extern const struct dds_entity_deriver dds_entity_deriver_cyclonedds;
|
||||
extern const struct dds_entity_deriver *dds_entity_deriver_table[];
|
||||
|
||||
dds_return_t dds_entity_deriver_dummy_close (struct dds_entity *e);
|
||||
void dds_entity_deriver_dummy_interrupt (struct dds_entity *e);
|
||||
void dds_entity_deriver_dummy_close (struct dds_entity *e);
|
||||
dds_return_t dds_entity_deriver_dummy_delete (struct dds_entity *e);
|
||||
dds_return_t dds_entity_deriver_dummy_set_qos (struct dds_entity *e, const dds_qos_t *qos, bool enabled);
|
||||
dds_return_t dds_entity_deriver_dummy_validate_status (uint32_t mask);
|
||||
|
||||
|
||||
inline dds_return_t dds_entity_deriver_close (struct dds_entity *e) {
|
||||
return (dds_entity_deriver_table[e->m_kind]->close) (e);
|
||||
inline void dds_entity_deriver_interrupt (struct dds_entity *e) {
|
||||
(dds_entity_deriver_table[e->m_kind]->interrupt) (e);
|
||||
}
|
||||
inline void dds_entity_deriver_close (struct dds_entity *e) {
|
||||
(dds_entity_deriver_table[e->m_kind]->close) (e);
|
||||
}
|
||||
inline dds_return_t dds_entity_deriver_delete (struct dds_entity *e) {
|
||||
return dds_entity_deriver_table[e->m_kind]->delete (e);
|
||||
|
@ -209,6 +200,36 @@ inline bool dds_entity_supports_validate_status (struct dds_entity *e) {
|
|||
return dds_entity_deriver_table[e->m_kind]->validate_status != dds_entity_deriver_dummy_validate_status;
|
||||
}
|
||||
|
||||
typedef struct dds_cyclonedds_entity {
|
||||
struct dds_entity m_entity;
|
||||
|
||||
ddsrt_mutex_t m_mutex;
|
||||
ddsrt_cond_t m_cond;
|
||||
ddsrt_avl_tree_t m_domains;
|
||||
uint32_t threadmon_count;
|
||||
struct ddsi_threadmon *threadmon;
|
||||
} dds_cyclonedds_entity;
|
||||
|
||||
typedef struct dds_domain {
|
||||
struct dds_entity m_entity;
|
||||
|
||||
ddsrt_avl_node_t m_node; /* for dds_global.m_domains */
|
||||
dds_domainid_t m_id;
|
||||
ddsrt_avl_tree_t m_topics;
|
||||
struct cfgst *cfgst;
|
||||
|
||||
struct ddsi_sertopic *builtin_participant_topic;
|
||||
struct ddsi_sertopic *builtin_reader_topic;
|
||||
struct ddsi_sertopic *builtin_writer_topic;
|
||||
|
||||
struct local_orphan_writer *builtintopic_writer_participant;
|
||||
struct local_orphan_writer *builtintopic_writer_publications;
|
||||
struct local_orphan_writer *builtintopic_writer_subscriptions;
|
||||
|
||||
struct ddsi_builtin_topic_interface btif;
|
||||
struct q_globals gv;
|
||||
} dds_domain;
|
||||
|
||||
typedef struct dds_subscriber {
|
||||
struct dds_entity m_entity;
|
||||
} dds_subscriber;
|
||||
|
@ -279,12 +300,10 @@ typedef uint32_t dds_querycond_mask_t;
|
|||
|
||||
typedef struct dds_readcond {
|
||||
dds_entity m_entity;
|
||||
struct dds_rhc *m_rhc;
|
||||
uint32_t m_qminv;
|
||||
uint32_t m_sample_states;
|
||||
uint32_t m_view_states;
|
||||
uint32_t m_instance_states;
|
||||
nn_guid_t m_rd_guid;
|
||||
struct dds_readcond *m_next;
|
||||
struct {
|
||||
dds_querycondition_filter_fn m_filter;
|
||||
|
@ -304,22 +323,18 @@ typedef struct dds_attachment {
|
|||
|
||||
typedef struct dds_waitset {
|
||||
dds_entity m_entity;
|
||||
size_t nentities; /* [m_entity.m_mutex] */
|
||||
size_t ntriggered; /* [m_entity.m_mutex] */
|
||||
dds_attachment *entities; /* [m_entity.m_mutex] 0 .. ntriggered are triggred, ntriggred .. nentities are not */
|
||||
|
||||
/* Need a lock other than m_entity.m_mutex because the locking order an entity lock may not be
|
||||
acquired while holding an ancestor's lock, but a waitset must be capable of triggering on
|
||||
events on its parent */
|
||||
ddsrt_mutex_t wait_lock;
|
||||
ddsrt_cond_t wait_cond;
|
||||
size_t nentities; /* [wait_lock] */
|
||||
size_t ntriggered; /* [wait_lock] */
|
||||
dds_attachment *entities; /* [wait_lock] 0 .. ntriggered are triggred, ntriggred .. nentities are not */
|
||||
} dds_waitset;
|
||||
|
||||
/* Globals */
|
||||
|
||||
typedef struct dds_globals {
|
||||
int32_t m_init_count;
|
||||
ddsrt_avl_tree_t m_domains;
|
||||
ddsrt_mutex_t m_mutex;
|
||||
uint32_t threadmon_count;
|
||||
struct ddsi_threadmon *threadmon;
|
||||
} dds_globals;
|
||||
|
||||
DDS_EXPORT extern dds_globals dds_global;
|
||||
DDS_EXPORT extern dds_cyclonedds_entity dds_global;
|
||||
|
||||
#if defined (__cplusplus)
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "dds__participant.h"
|
||||
#include "dds__types.h"
|
||||
#include "dds__builtin.h"
|
||||
#include "dds__entity.h"
|
||||
#include "dds__subscriber.h"
|
||||
#include "dds__write.h"
|
||||
#include "dds__writer.h"
|
||||
|
@ -46,9 +47,15 @@ dds_entity_t dds__get_builtin_topic (dds_entity_t entity, dds_entity_t topic)
|
|||
dds_entity_t tp;
|
||||
dds_return_t rc;
|
||||
dds_entity *e;
|
||||
dds_participant *par;
|
||||
|
||||
if ((rc = dds_entity_pin (entity, &e)) < 0)
|
||||
return rc;
|
||||
if ((par = dds_entity_participant (e)) == NULL)
|
||||
{
|
||||
dds_entity_unpin (e);
|
||||
return DDS_RETCODE_ILLEGAL_OPERATION;
|
||||
}
|
||||
|
||||
struct ddsi_sertopic *sertopic;
|
||||
switch (topic)
|
||||
|
@ -69,7 +76,7 @@ dds_entity_t dds__get_builtin_topic (dds_entity_t entity, dds_entity_t topic)
|
|||
}
|
||||
|
||||
dds_qos_t *qos = dds__create_builtin_qos ();
|
||||
tp = dds_create_topic_arbitrary (e->m_participant->m_hdllink.hdl, sertopic, qos, NULL, NULL);
|
||||
tp = dds_create_topic_arbitrary (par->m_entity.m_hdllink.hdl, sertopic, qos, NULL, NULL);
|
||||
dds_delete_qos (qos);
|
||||
dds_entity_unpin (e);
|
||||
return tp;
|
||||
|
@ -155,7 +162,7 @@ static bool dds__builtin_is_builtintopic (const struct ddsi_sertopic *tp, void *
|
|||
return tp->ops == &ddsi_sertopic_ops_builtintopic;
|
||||
}
|
||||
|
||||
static bool dds__builtin_is_visible (const nn_guid_t *guid, nn_vendorid_t vendorid, void *vdomain)
|
||||
static bool dds__builtin_is_visible (const ddsi_guid_t *guid, nn_vendorid_t vendorid, void *vdomain)
|
||||
{
|
||||
(void) vdomain;
|
||||
if (is_builtin_endpoint (guid->entityid, vendorid))
|
||||
|
@ -163,7 +170,7 @@ static bool dds__builtin_is_visible (const nn_guid_t *guid, nn_vendorid_t vendor
|
|||
return true;
|
||||
}
|
||||
|
||||
static struct ddsi_tkmap_instance *dds__builtin_get_tkmap_entry (const struct nn_guid *guid, void *vdomain)
|
||||
static struct ddsi_tkmap_instance *dds__builtin_get_tkmap_entry (const struct ddsi_guid *guid, void *vdomain)
|
||||
{
|
||||
struct dds_domain *domain = vdomain;
|
||||
struct ddsi_tkmap_instance *tk;
|
||||
|
|
|
@ -11,14 +11,14 @@
|
|||
*/
|
||||
#include <string.h>
|
||||
|
||||
#include "dds/ddsrt/environ.h"
|
||||
#include "dds/ddsrt/process.h"
|
||||
#include "dds/ddsrt/heap.h"
|
||||
#include "dds__init.h"
|
||||
#include "dds__rhc.h"
|
||||
#include "dds/ddsc/dds_rhc.h"
|
||||
#include "dds__domain.h"
|
||||
#include "dds__builtin.h"
|
||||
#include "dds__whc_builtintopic.h"
|
||||
#include "dds__entity.h"
|
||||
#include "dds/ddsi/ddsi_iid.h"
|
||||
#include "dds/ddsi/ddsi_tkmap.h"
|
||||
#include "dds/ddsi/ddsi_serdata.h"
|
||||
|
@ -27,7 +27,16 @@
|
|||
#include "dds/ddsi/q_config.h"
|
||||
#include "dds/ddsi/q_gc.h"
|
||||
#include "dds/ddsi/q_globals.h"
|
||||
#include "dds/version.h"
|
||||
|
||||
static dds_return_t dds_domain_free (dds_entity *vdomain);
|
||||
|
||||
const struct dds_entity_deriver dds_entity_deriver_domain = {
|
||||
.interrupt = dds_entity_deriver_dummy_interrupt,
|
||||
.close = dds_entity_deriver_dummy_close,
|
||||
.delete = dds_domain_free,
|
||||
.set_qos = dds_entity_deriver_dummy_set_qos,
|
||||
.validate_status = dds_entity_deriver_dummy_validate_status
|
||||
};
|
||||
|
||||
static int dds_domain_compare (const void *va, const void *vb)
|
||||
{
|
||||
|
@ -39,14 +48,20 @@ static int dds_domain_compare (const void *va, const void *vb)
|
|||
static const ddsrt_avl_treedef_t dds_domaintree_def = DDSRT_AVL_TREEDEF_INITIALIZER (
|
||||
offsetof (dds_domain, m_node), offsetof (dds_domain, m_id), dds_domain_compare, 0);
|
||||
|
||||
static dds_return_t dds_domain_init (dds_domain *domain, dds_domainid_t domain_id)
|
||||
static dds_return_t dds_domain_init (dds_domain *domain, dds_domainid_t domain_id, const char *config)
|
||||
{
|
||||
dds_return_t ret = DDS_RETCODE_OK;
|
||||
char * uri = NULL;
|
||||
uint32_t len;
|
||||
dds_entity_t domain_handle;
|
||||
|
||||
if ((domain_handle = dds_entity_init (&domain->m_entity, &dds_global.m_entity, DDS_KIND_DOMAIN, NULL, NULL, 0)) < 0)
|
||||
return domain_handle;
|
||||
domain->m_entity.m_domain = domain;
|
||||
domain->m_entity.m_flags |= DDS_ENTITY_IMPLICIT;
|
||||
domain->m_entity.m_iid = ddsi_iid_gen ();
|
||||
|
||||
domain->gv.tstart = now ();
|
||||
domain->m_refc = 1;
|
||||
ddsrt_avl_init (&dds_topictree_def, &domain->m_topics);
|
||||
|
||||
/* | domain_id | domain id in config | result
|
||||
|
@ -72,8 +87,7 @@ static dds_return_t dds_domain_init (dds_domain *domain, dds_domainid_t domain_i
|
|||
a value (if nothing has been set previously, it a warning is good
|
||||
enough) */
|
||||
|
||||
(void) ddsrt_getenv ("CYCLONEDDS_URI", &uri);
|
||||
domain->cfgst = config_init (uri, &domain->gv.config, domain_id);
|
||||
domain->cfgst = config_init (config, &domain->gv.config, domain_id);
|
||||
if (domain->cfgst == NULL)
|
||||
{
|
||||
DDS_ILOG (DDS_LC_CONFIG, domain_id, "Failed to parse configuration XML file %s\n", uri);
|
||||
|
@ -152,9 +166,9 @@ static dds_return_t dds_domain_init (dds_domain *domain, dds_domainid_t domain_i
|
|||
|
||||
if (domain->gv.config.liveliness_monitoring)
|
||||
ddsi_threadmon_register_domain (dds_global.threadmon, &domain->gv);
|
||||
dds_entity_init_complete (&domain->m_entity);
|
||||
return DDS_RETCODE_OK;
|
||||
|
||||
rtps_stop (&domain->gv);
|
||||
fail_rtps_start:
|
||||
if (domain->gv.config.liveliness_monitoring && dds_global.threadmon_count == 1)
|
||||
ddsi_threadmon_stop (dds_global.threadmon);
|
||||
|
@ -170,43 +184,23 @@ fail_rtps_init:
|
|||
fail_rtps_config:
|
||||
config_fini (domain->cfgst);
|
||||
fail_config:
|
||||
dds_handle_delete (&domain->m_entity.m_hdllink);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void dds_domain_fini (struct dds_domain *domain)
|
||||
{
|
||||
rtps_stop (&domain->gv);
|
||||
dds__builtin_fini (domain);
|
||||
|
||||
if (domain->gv.config.liveliness_monitoring)
|
||||
ddsi_threadmon_unregister_domain (dds_global.threadmon, &domain->gv);
|
||||
|
||||
rtps_fini (&domain->gv);
|
||||
|
||||
ddsrt_mutex_lock (&dds_global.m_mutex);
|
||||
if (domain->gv.config.liveliness_monitoring && --dds_global.threadmon_count == 0)
|
||||
{
|
||||
ddsi_threadmon_stop (dds_global.threadmon);
|
||||
ddsi_threadmon_free (dds_global.threadmon);
|
||||
}
|
||||
ddsrt_mutex_unlock (&dds_global.m_mutex);
|
||||
|
||||
config_fini (domain->cfgst);
|
||||
}
|
||||
|
||||
dds_domain *dds_domain_find_locked (dds_domainid_t id)
|
||||
{
|
||||
return ddsrt_avl_lookup (&dds_domaintree_def, &dds_global.m_domains, &id);
|
||||
}
|
||||
|
||||
dds_return_t dds_domain_create (dds_domain **domain_out, dds_domainid_t id)
|
||||
dds_return_t dds_domain_create_internal (dds_domain **domain_out, dds_domainid_t id, bool use_existing, const char *config)
|
||||
{
|
||||
struct dds_domain *dom = NULL;
|
||||
struct dds_domain *dom;
|
||||
dds_return_t ret;
|
||||
|
||||
/* FIXME: should perhaps lock parent object just like everywhere */
|
||||
ddsrt_mutex_lock (&dds_global.m_mutex);
|
||||
|
||||
/* FIXME: hack around default domain ids, not yet being able to handle multiple domains simultaneously */
|
||||
retry:
|
||||
if (id != DDS_DOMAIN_DEFAULT)
|
||||
{
|
||||
if ((dom = dds_domain_find_locked (id)) == NULL)
|
||||
|
@ -225,41 +219,94 @@ dds_return_t dds_domain_create (dds_domain **domain_out, dds_domainid_t id)
|
|||
switch (ret)
|
||||
{
|
||||
case DDS_RETCODE_OK:
|
||||
dom->m_refc++;
|
||||
*domain_out = dom;
|
||||
break;
|
||||
case DDS_RETCODE_NOT_FOUND:
|
||||
dom = dds_alloc (sizeof (*dom));
|
||||
if ((ret = dds_domain_init (dom, id)) < 0)
|
||||
dds_free (dom);
|
||||
if (!use_existing)
|
||||
{
|
||||
ret = DDS_RETCODE_PRECONDITION_NOT_MET;
|
||||
break;
|
||||
}
|
||||
ddsrt_mutex_lock (&dom->m_entity.m_mutex);
|
||||
if (dds_handle_is_closed (&dom->m_entity.m_hdllink))
|
||||
{
|
||||
ddsrt_mutex_unlock (&dom->m_entity.m_mutex);
|
||||
ddsrt_cond_wait (&dds_global.m_cond, &dds_global.m_mutex);
|
||||
goto retry;
|
||||
}
|
||||
else
|
||||
{
|
||||
ddsrt_avl_insert (&dds_domaintree_def, &dds_global.m_domains, dom);
|
||||
dds_entity_add_ref_locked (&dom->m_entity);
|
||||
ddsrt_mutex_unlock (&dom->m_entity.m_mutex);
|
||||
*domain_out = dom;
|
||||
}
|
||||
break;
|
||||
case DDS_RETCODE_PRECONDITION_NOT_MET:
|
||||
DDS_ILOG (DDS_LC_ERROR, id, "Inconsistent domain configuration detected: domain on configuration: %"PRIu32", domain %"PRIu32"\n", dom->m_id, id);
|
||||
case DDS_RETCODE_NOT_FOUND:
|
||||
dom = dds_alloc (sizeof (*dom));
|
||||
if ((ret = dds_domain_init (dom, id, config)) < 0)
|
||||
dds_free (dom);
|
||||
else
|
||||
{
|
||||
ddsrt_mutex_lock (&dom->m_entity.m_mutex);
|
||||
ddsrt_avl_insert (&dds_domaintree_def, &dds_global.m_domains, dom);
|
||||
dds_entity_register_child (&dds_global.m_entity, &dom->m_entity);
|
||||
dds_entity_add_ref_locked (&dom->m_entity);
|
||||
ddsrt_mutex_unlock (&dom->m_entity.m_mutex);
|
||||
*domain_out = dom;
|
||||
}
|
||||
break;
|
||||
}
|
||||
ddsrt_mutex_unlock (&dds_global.m_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void dds_domain_free (dds_domain *domain)
|
||||
dds_return_t dds_create_domain(const dds_domainid_t domain, const char *config)
|
||||
{
|
||||
dds_domain *dom;
|
||||
dds_entity_t ret;
|
||||
|
||||
if (domain == DDS_DOMAIN_DEFAULT || config == NULL)
|
||||
return DDS_RETCODE_BAD_PARAMETER;
|
||||
|
||||
/* Make sure DDS instance is initialized. */
|
||||
if ((ret = dds_init ()) < 0)
|
||||
goto err_dds_init;
|
||||
|
||||
if ((ret = dds_domain_create_internal (&dom, domain, false, config)) < 0)
|
||||
goto err_domain_create;
|
||||
|
||||
return DDS_RETCODE_OK;
|
||||
|
||||
err_domain_create:
|
||||
dds_delete_impl_pinned (&dds_global.m_entity, DIS_EXPLICIT);
|
||||
err_dds_init:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static dds_return_t dds_domain_free (dds_entity *vdomain)
|
||||
{
|
||||
struct dds_domain *domain = (struct dds_domain *) vdomain;
|
||||
rtps_stop (&domain->gv);
|
||||
dds__builtin_fini (domain);
|
||||
|
||||
if (domain->gv.config.liveliness_monitoring)
|
||||
ddsi_threadmon_unregister_domain (dds_global.threadmon, &domain->gv);
|
||||
|
||||
rtps_fini (&domain->gv);
|
||||
|
||||
/* tearing down the top-level object has more consequences, so it waits until signalled that all
|
||||
domains have been removed */
|
||||
ddsrt_mutex_lock (&dds_global.m_mutex);
|
||||
if (--domain->m_refc != 0)
|
||||
if (domain->gv.config.liveliness_monitoring && --dds_global.threadmon_count == 0)
|
||||
{
|
||||
ddsrt_mutex_unlock (&dds_global.m_mutex);
|
||||
}
|
||||
else
|
||||
{
|
||||
ddsrt_avl_delete (&dds_domaintree_def, &dds_global.m_domains, domain);
|
||||
ddsrt_mutex_unlock (&dds_global.m_mutex);
|
||||
dds_domain_fini (domain);
|
||||
dds_free (domain);
|
||||
ddsi_threadmon_stop (dds_global.threadmon);
|
||||
ddsi_threadmon_free (dds_global.threadmon);
|
||||
}
|
||||
|
||||
ddsrt_avl_delete (&dds_domaintree_def, &dds_global.m_domains, domain);
|
||||
dds_entity_final_deinit_before_free (vdomain);
|
||||
config_fini (domain->cfgst);
|
||||
dds_free (vdomain);
|
||||
ddsrt_cond_broadcast (&dds_global.m_cond);
|
||||
ddsrt_mutex_unlock (&dds_global.m_mutex);
|
||||
return DDS_RETCODE_NO_DATA;
|
||||
}
|
||||
|
||||
#include "dds__entity.h"
|
||||
|
@ -295,7 +342,8 @@ void dds_write_set_batch (bool enable)
|
|||
/* FIXME: get channels + latency budget working and get rid of this; in the mean time, any ugly hack will do. */
|
||||
struct dds_domain *dom;
|
||||
dds_domainid_t next_id = 0;
|
||||
dds_init ();
|
||||
if (dds_init () < 0)
|
||||
return;
|
||||
ddsrt_mutex_lock (&dds_global.m_mutex);
|
||||
while ((dom = ddsrt_avl_lookup_succ_eq (&dds_domaintree_def, &dds_global.m_domains, &next_id)) != NULL)
|
||||
{
|
||||
|
@ -306,7 +354,7 @@ void dds_write_set_batch (bool enable)
|
|||
|
||||
dds_instance_handle_t last_iid = 0;
|
||||
struct dds_entity *e;
|
||||
while (dom && (e = ddsrt_avl_lookup_succ (&dds_entity_children_td, &dom->m_ppants, &last_iid)) != NULL)
|
||||
while (dom && (e = ddsrt_avl_lookup_succ (&dds_entity_children_td, &dom->m_entity.m_children, &last_iid)) != NULL)
|
||||
{
|
||||
struct dds_entity *x;
|
||||
last_iid = e->m_iid;
|
||||
|
@ -321,5 +369,5 @@ void dds_write_set_batch (bool enable)
|
|||
}
|
||||
}
|
||||
ddsrt_mutex_unlock (&dds_global.m_mutex);
|
||||
dds_fini ();
|
||||
dds_delete_impl_pinned (&dds_global.m_entity, DIS_EXPLICIT);
|
||||
}
|
||||
|
|
|
@ -40,10 +40,15 @@ const struct dds_entity_deriver *dds_entity_deriver_table[] = {
|
|||
[DDS_KIND_COND_QUERY] = &dds_entity_deriver_readcondition,
|
||||
[DDS_KIND_COND_GUARD] = &dds_entity_deriver_guardcondition,
|
||||
[DDS_KIND_WAITSET] = &dds_entity_deriver_waitset,
|
||||
[DDS_KIND_DOMAIN] = &dds_entity_deriver_domain,
|
||||
[DDS_KIND_CYCLONEDDS] = &dds_entity_deriver_cyclonedds
|
||||
};
|
||||
|
||||
dds_return_t dds_entity_deriver_dummy_close (struct dds_entity *e) {
|
||||
(void) e; return DDS_RETCODE_OK;
|
||||
void dds_entity_deriver_dummy_interrupt (struct dds_entity *e) {
|
||||
(void) e;
|
||||
}
|
||||
void dds_entity_deriver_dummy_close (struct dds_entity *e) {
|
||||
(void) e;
|
||||
}
|
||||
dds_return_t dds_entity_deriver_dummy_delete (struct dds_entity *e) {
|
||||
(void) e; return DDS_RETCODE_OK;
|
||||
|
@ -55,7 +60,8 @@ dds_return_t dds_entity_deriver_dummy_validate_status (uint32_t mask) {
|
|||
(void) mask; return DDS_RETCODE_ILLEGAL_OPERATION;
|
||||
}
|
||||
|
||||
extern inline dds_return_t dds_entity_deriver_close (struct dds_entity *e);
|
||||
extern inline void dds_entity_deriver_interrupt (struct dds_entity *e);
|
||||
extern inline void dds_entity_deriver_close (struct dds_entity *e);
|
||||
extern inline dds_return_t dds_entity_deriver_delete (struct dds_entity *e);
|
||||
extern inline dds_return_t dds_entity_deriver_set_qos (struct dds_entity *e, const dds_qos_t *qos, bool enabled);
|
||||
extern inline dds_return_t dds_entity_deriver_validate_status (struct dds_entity *e, uint32_t mask);
|
||||
|
@ -73,23 +79,12 @@ const ddsrt_avl_treedef_t dds_entity_children_td = DDSRT_AVL_TREEDEF_INITIALIZER
|
|||
|
||||
static void dds_entity_observers_signal (dds_entity *observed, uint32_t status);
|
||||
static void dds_entity_observers_signal_delete (dds_entity *observed);
|
||||
static void dds_entity_observers_delete (dds_entity *observed);
|
||||
|
||||
void dds_entity_add_ref_locked (dds_entity *e)
|
||||
{
|
||||
dds_handle_add_ref (&e->m_hdllink);
|
||||
}
|
||||
|
||||
dds_domain *dds__entity_domain (dds_entity *e)
|
||||
{
|
||||
return e->m_domain;
|
||||
}
|
||||
|
||||
static dds_entity *dds__nonself_parent (dds_entity *e)
|
||||
{
|
||||
return e->m_parent == e ? NULL : e->m_parent;
|
||||
}
|
||||
|
||||
static bool entity_has_status (const dds_entity *e)
|
||||
{
|
||||
switch (e->m_kind)
|
||||
|
@ -105,6 +100,8 @@ static bool entity_has_status (const dds_entity *e)
|
|||
case DDS_KIND_COND_QUERY:
|
||||
case DDS_KIND_COND_GUARD:
|
||||
case DDS_KIND_WAITSET:
|
||||
case DDS_KIND_DOMAIN:
|
||||
case DDS_KIND_CYCLONEDDS:
|
||||
break;
|
||||
case DDS_KIND_DONTCARE:
|
||||
abort ();
|
||||
|
@ -117,12 +114,13 @@ dds_entity_t dds_entity_init (dds_entity *e, dds_entity *parent, dds_entity_kind
|
|||
{
|
||||
dds_handle_t handle;
|
||||
|
||||
assert ((kind == DDS_KIND_PARTICIPANT) == (parent == NULL));
|
||||
assert ((kind == DDS_KIND_CYCLONEDDS) == (parent == NULL));
|
||||
assert (e);
|
||||
|
||||
e->m_kind = kind;
|
||||
e->m_qos = qos;
|
||||
e->m_cb_count = 0;
|
||||
e->m_cb_pending_count = 0;
|
||||
e->m_observers = NULL;
|
||||
|
||||
/* TODO: CHAM-96: Implement dynamic enabling of entity. */
|
||||
|
@ -143,14 +141,14 @@ dds_entity_t dds_entity_init (dds_entity *e, dds_entity *parent, dds_entity_kind
|
|||
{
|
||||
e->m_parent = parent;
|
||||
e->m_domain = parent->m_domain;
|
||||
e->m_participant = parent->m_participant;
|
||||
ddsrt_avl_init (&dds_entity_children_td, &e->m_children);
|
||||
}
|
||||
else
|
||||
{
|
||||
e->m_participant = e;
|
||||
e->m_parent = e;
|
||||
assert (kind == DDS_KIND_CYCLONEDDS);
|
||||
e->m_parent = NULL;
|
||||
e->m_domain = NULL;
|
||||
}
|
||||
ddsrt_avl_init (&dds_entity_children_td, &e->m_children);
|
||||
|
||||
dds_reset_listener (&e->m_listener);
|
||||
if (listener)
|
||||
|
@ -162,13 +160,26 @@ dds_entity_t dds_entity_init (dds_entity *e, dds_entity *parent, dds_entity_kind
|
|||
ddsrt_mutex_unlock (&parent->m_observers_lock);
|
||||
}
|
||||
|
||||
if ((handle = dds_handle_create (&e->m_hdllink)) <= 0)
|
||||
return (dds_entity_t) handle;
|
||||
if (kind == DDS_KIND_CYCLONEDDS)
|
||||
{
|
||||
if ((handle = dds_handle_register_special (&e->m_hdllink, DDS_CYCLONEDDS_HANDLE)) <= 0)
|
||||
return (dds_entity_t) handle;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((handle = dds_handle_create (&e->m_hdllink)) <= 0)
|
||||
return (dds_entity_t) handle;
|
||||
}
|
||||
|
||||
/* An dds_handle_t is directly used as dds_entity_t. */
|
||||
return (dds_entity_t) handle;
|
||||
}
|
||||
|
||||
void dds_entity_init_complete (dds_entity *entity)
|
||||
{
|
||||
dds_handle_unpend (&entity->m_hdllink);
|
||||
}
|
||||
|
||||
void dds_entity_register_child (dds_entity *parent, dds_entity *child)
|
||||
{
|
||||
assert (child->m_iid != 0);
|
||||
|
@ -176,11 +187,6 @@ void dds_entity_register_child (dds_entity *parent, dds_entity *child)
|
|||
ddsrt_avl_insert (&dds_entity_children_td, &parent->m_children, child);
|
||||
}
|
||||
|
||||
dds_return_t dds_delete (dds_entity_t entity)
|
||||
{
|
||||
return dds_delete_impl (entity, false);
|
||||
}
|
||||
|
||||
static dds_entity *next_non_topic_child (ddsrt_avl_tree_t *remaining_children)
|
||||
{
|
||||
ddsrt_avl_iter_t it;
|
||||
|
@ -192,45 +198,145 @@ static dds_entity *next_non_topic_child (ddsrt_avl_tree_t *remaining_children)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
dds_return_t dds_delete_impl (dds_entity_t entity, bool keep_if_explicit)
|
||||
#define TRACE_DELETE 0 /* FIXME: use DDS_LOG for this */
|
||||
#if TRACE_DELETE
|
||||
static const char *entity_kindstr (dds_entity_kind_t kind)
|
||||
{
|
||||
switch (kind)
|
||||
{
|
||||
case DDS_KIND_TOPIC: return "topic";
|
||||
case DDS_KIND_READER: return "reader";
|
||||
case DDS_KIND_WRITER: return "writer";
|
||||
case DDS_KIND_PUBLISHER: return "publisher";
|
||||
case DDS_KIND_SUBSCRIBER: return "subscriber";
|
||||
case DDS_KIND_PARTICIPANT: return "participant";
|
||||
case DDS_KIND_COND_READ: return "readcond";
|
||||
case DDS_KIND_COND_QUERY: return "querycond";
|
||||
case DDS_KIND_COND_GUARD: return "guardcond";
|
||||
case DDS_KIND_WAITSET: return "waitset";
|
||||
case DDS_KIND_DOMAIN: return "domain";
|
||||
case DDS_KIND_CYCLONEDDS: return "cyclonedds";
|
||||
case DDS_KIND_DONTCARE: break;
|
||||
}
|
||||
return "UNDEF";
|
||||
}
|
||||
|
||||
static void print_delete (const dds_entity *e, enum delete_impl_state delstate , dds_instance_handle_t iid)
|
||||
{
|
||||
unsigned cm = ddsrt_atomic_ld32 (&e->m_hdllink.cnt_flags);
|
||||
printf ("delete(%p, delstate %s, iid %"PRIx64"): %s%s %d pin %u refc %u %s %s\n",
|
||||
(void *) e, (delstate == DIS_IMPLICIT) ? "implicit" : (delstate == DIS_EXPLICIT) ? "explicit" : "from_parent", iid,
|
||||
entity_kindstr (e->m_kind), (e->m_flags & DDS_ENTITY_IMPLICIT) ? " [implicit]" : "",
|
||||
e->m_hdllink.hdl, cm & 0xfff, (cm >> 12) & 0xffff, (cm & 0x80000000) ? "closed" : "open",
|
||||
ddsrt_avl_is_empty (&e->m_children) ? "childless" : "has-children");
|
||||
}
|
||||
#endif
|
||||
|
||||
static dds_return_t dds_delete_impl (dds_entity_t entity, enum delete_impl_state delstate);
|
||||
|
||||
dds_return_t dds_delete (dds_entity_t entity)
|
||||
{
|
||||
return dds_delete_impl (entity, DIS_EXPLICIT);
|
||||
}
|
||||
|
||||
void dds_entity_final_deinit_before_free (dds_entity *e)
|
||||
{
|
||||
dds_delete_qos (e->m_qos);
|
||||
ddsrt_cond_destroy (&e->m_cond);
|
||||
ddsrt_cond_destroy (&e->m_observers_cond);
|
||||
ddsrt_mutex_destroy (&e->m_mutex);
|
||||
ddsrt_mutex_destroy (&e->m_observers_lock);
|
||||
}
|
||||
|
||||
static dds_return_t dds_delete_impl (dds_entity_t entity, enum delete_impl_state delstate)
|
||||
{
|
||||
dds_time_t timeout = DDS_SECS(10);
|
||||
dds_entity *e;
|
||||
dds_return_t ret;
|
||||
if ((ret = dds_entity_pin (entity, &e)) < 0)
|
||||
return ret;
|
||||
else
|
||||
return dds_delete_impl_pinned (e, delstate);
|
||||
}
|
||||
|
||||
dds_return_t dds_delete_impl_pinned (dds_entity *e, enum delete_impl_state delstate)
|
||||
{
|
||||
dds_entity *child;
|
||||
dds_return_t ret;
|
||||
dds_return_t rc;
|
||||
|
||||
if ((rc = dds_entity_pin (entity, &e)) < 0)
|
||||
return rc;
|
||||
/* Any number of threads pinning it, possibly in delete, or having pinned it and
|
||||
trying to acquire m_mutex */
|
||||
|
||||
ddsrt_mutex_lock (&e->m_mutex);
|
||||
if (keep_if_explicit == true && (e->m_flags & DDS_ENTITY_IMPLICIT) == 0)
|
||||
#if TRACE_DELETE
|
||||
print_delete (e, delstate, iid);
|
||||
#endif
|
||||
|
||||
/* If another thread was racing us in delete, it will have set the CLOSING flag
|
||||
while holding m_mutex and we had better bail out. */
|
||||
if (dds_handle_is_closed (&e->m_hdllink))
|
||||
{
|
||||
ddsrt_mutex_unlock (&e->m_mutex);
|
||||
dds_entity_unpin (e);
|
||||
dds_entity_unlock (e);
|
||||
return DDS_RETCODE_OK;
|
||||
}
|
||||
|
||||
/* Ignore children calling up to delete an implicit parent if there are still
|
||||
(or again) children */
|
||||
if (delstate == DIS_IMPLICIT)
|
||||
{
|
||||
if (!((e->m_flags & DDS_ENTITY_IMPLICIT) && ddsrt_avl_is_empty (&e->m_children)))
|
||||
{
|
||||
dds_entity_unlock (e);
|
||||
return DDS_RETCODE_OK;
|
||||
}
|
||||
}
|
||||
|
||||
/* Drop reference, atomically setting CLOSING if no other references remain.
|
||||
FIXME: that's not quite right: this is really only for topics. After a call
|
||||
to delete, the handle ought to become invalid even if the topic stays (and
|
||||
should perhaps even be revivable via find_topic). */
|
||||
if (! dds_handle_drop_ref (&e->m_hdllink))
|
||||
{
|
||||
ddsrt_mutex_unlock (&e->m_mutex);
|
||||
dds_entity_unpin (e);
|
||||
dds_entity_unlock (e);
|
||||
return DDS_RETCODE_OK;
|
||||
}
|
||||
|
||||
/* No threads pinning it anymore, no need to worry about other threads deleting
|
||||
it, but there can still be plenty of threads that have it pinned and are
|
||||
trying to acquire m_mutex to do their thing (including creating children,
|
||||
attaching to waitsets, &c.) */
|
||||
|
||||
assert (dds_handle_is_closed (&e->m_hdllink));
|
||||
|
||||
/* Trigger blocked threads (and, still, delete DDSI reader/writer to trigger
|
||||
continued cleanup -- while that's quite safe given that GUIDs don't get
|
||||
reused quickly, it needs an update) */
|
||||
dds_entity_deriver_interrupt (e);
|
||||
|
||||
/* Prevent further listener invocations; dds_set_status_mask locks m_mutex and
|
||||
checks for a pending delete to guarantee that once we clear the mask here,
|
||||
no new listener invocations will occur beyond those already in progress.
|
||||
(FIXME: or committed to? I think in-progress only, better check.) */
|
||||
ddsrt_mutex_lock (&e->m_observers_lock);
|
||||
if (entity_has_status (e))
|
||||
ddsrt_atomic_and32 (&e->m_status.m_status_and_mask, SAM_STATUS_MASK);
|
||||
dds_reset_listener (&e->m_listener);
|
||||
|
||||
/* Signal observers that this entity will be deleted and wait for
|
||||
all listeners to complete. */
|
||||
ddsrt_mutex_unlock (&e->m_mutex);
|
||||
dds_entity_observers_signal_delete (e);
|
||||
while (e->m_cb_count > 0)
|
||||
|
||||
/* wait for all listeners to complete - FIXME: rely on pincount instead?
|
||||
that would require all listeners to pin the entity instead, but it
|
||||
would prevent them from doing much. */
|
||||
while (e->m_cb_pending_count > 0)
|
||||
ddsrt_cond_wait (&e->m_observers_cond, &e->m_observers_lock);
|
||||
ddsrt_mutex_unlock (&e->m_observers_lock);
|
||||
|
||||
/* Wait for all other threads to unpin the entity */
|
||||
dds_handle_close_wait (&e->m_hdllink);
|
||||
|
||||
/* Pin count dropped to one with CLOSING flag set: no other threads still
|
||||
in operations involving this entity */
|
||||
dds_entity_observers_signal_delete (e);
|
||||
dds_entity_deriver_close (e);
|
||||
|
||||
/*
|
||||
* Recursively delete children.
|
||||
*
|
||||
|
@ -248,106 +354,123 @@ dds_return_t dds_delete_impl (dds_entity_t entity, bool keep_if_explicit)
|
|||
*
|
||||
* To circumvent the problem. We ignore topics in the first loop.
|
||||
*/
|
||||
ret = DDS_RETCODE_OK;
|
||||
ddsrt_mutex_lock (&e->m_mutex);
|
||||
while ((child = next_non_topic_child (&e->m_children)) && ret == DDS_RETCODE_OK)
|
||||
while ((child = next_non_topic_child (&e->m_children)) != NULL)
|
||||
{
|
||||
/* FIXME: dds_delete can fail if the child is being deleted in parallel, in which case: wait */
|
||||
dds_entity_t child_handle = child->m_hdllink.hdl;
|
||||
ddsrt_mutex_unlock (&e->m_mutex);
|
||||
ret = dds_delete (child_handle);
|
||||
(void) dds_delete_impl (child_handle, DIS_FROM_PARENT);
|
||||
ddsrt_mutex_lock (&e->m_mutex);
|
||||
}
|
||||
while ((child = ddsrt_avl_find_min (&dds_entity_children_td, &e->m_children)) != NULL && ret == DDS_RETCODE_OK)
|
||||
while ((child = ddsrt_avl_find_min (&dds_entity_children_td, &e->m_children)) != NULL)
|
||||
{
|
||||
assert (dds_entity_kind (child) == DDS_KIND_TOPIC);
|
||||
dds_entity_t child_handle = child->m_hdllink.hdl;
|
||||
ddsrt_mutex_unlock (&e->m_mutex);
|
||||
ret = dds_delete (child_handle);
|
||||
(void) dds_delete_impl (child_handle, DIS_FROM_PARENT);
|
||||
ddsrt_mutex_lock (&e->m_mutex);
|
||||
}
|
||||
ddsrt_mutex_unlock (&e->m_mutex);
|
||||
if (ret == DDS_RETCODE_OK)
|
||||
ret = dds_entity_deriver_close (e);
|
||||
|
||||
dds_entity_unpin (e);
|
||||
if (ret == DDS_RETCODE_OK)
|
||||
/* The dds_handle_delete will wait until the last active claim on that handle is
|
||||
released. It is possible that this last release will be done by a thread that was
|
||||
kicked during the close(). */
|
||||
ret = dds_handle_delete (&e->m_hdllink);
|
||||
assert (ret == DDS_RETCODE_OK);
|
||||
(void) ret;
|
||||
|
||||
/* Remove from parent; schedule deletion of parent if it was created implicitly, no
|
||||
longer has any remaining children, and we didn't arrive here as a consequence of
|
||||
deleting the parent. */
|
||||
dds_entity *parent_to_delete = NULL;
|
||||
if (e->m_parent != NULL)
|
||||
{
|
||||
/* The dds_handle_delete will wait until the last active claim on that handle
|
||||
* is released. It is possible that this last release will be done by a thread
|
||||
* that was kicked during the close(). */
|
||||
if ((ret = dds_handle_delete (&e->m_hdllink, timeout)) != DDS_RETCODE_OK)
|
||||
return ret;
|
||||
}
|
||||
struct dds_entity * const p = e->m_parent;
|
||||
|
||||
if (ret == DDS_RETCODE_OK)
|
||||
{
|
||||
/* Remove all possible observers. */
|
||||
dds_entity_observers_delete (e);
|
||||
ddsrt_mutex_lock (&p->m_mutex);
|
||||
assert (ddsrt_avl_lookup (&dds_entity_children_td, &p->m_children, &e->m_iid) != NULL);
|
||||
ddsrt_avl_delete (&dds_entity_children_td, &p->m_children, e);
|
||||
/* trigger parent in case it is waiting in delete */
|
||||
ddsrt_cond_broadcast (&p->m_cond);
|
||||
|
||||
/* Remove from parent */
|
||||
dds_entity *parent;
|
||||
if ((parent = dds__nonself_parent(e)) != NULL)
|
||||
if (delstate != DIS_FROM_PARENT && (p->m_flags & DDS_ENTITY_IMPLICIT) && ddsrt_avl_is_empty (&p->m_children))
|
||||
{
|
||||
ddsrt_mutex_lock (&parent->m_mutex);
|
||||
assert (ddsrt_avl_lookup (&dds_entity_children_td, &parent->m_children, &e->m_iid) != NULL);
|
||||
ddsrt_avl_delete (&dds_entity_children_td, &parent->m_children, e);
|
||||
ddsrt_mutex_unlock (&parent->m_mutex);
|
||||
if ((ret = dds_entity_pin (p->m_hdllink.hdl, &parent_to_delete)) < 0)
|
||||
parent_to_delete = NULL;
|
||||
}
|
||||
|
||||
/* Do some specific deletion when needed. */
|
||||
ret = dds_entity_deriver_delete (e);
|
||||
ddsrt_mutex_unlock (&p->m_mutex);
|
||||
}
|
||||
|
||||
if (ret == DDS_RETCODE_OK)
|
||||
/* Do some specific deletion when needed */
|
||||
ret = dds_entity_deriver_delete (e);
|
||||
if (ret == DDS_RETCODE_NO_DATA)
|
||||
{
|
||||
dds_delete_qos (e->m_qos);
|
||||
ddsrt_cond_destroy (&e->m_cond);
|
||||
ddsrt_cond_destroy (&e->m_observers_cond);
|
||||
ddsrt_mutex_destroy (&e->m_mutex);
|
||||
ddsrt_mutex_destroy (&e->m_observers_lock);
|
||||
/* Bootstrapping and its inverse are always a tricky business, and here it is no different:
|
||||
deleting the pseudo-top-level object tears down all kinds of stuff that is supposed to
|
||||
remain in existence (like the entire platform abstraction) and so it must be the final
|
||||
call. Thus, we rely on it to call "dds_entity_final_deinit_before_free" and return a
|
||||
special error code that we don't pass on to the caller. */
|
||||
ret = DDS_RETCODE_OK;
|
||||
}
|
||||
else if (ret != DDS_RETCODE_OK)
|
||||
{
|
||||
if (parent_to_delete)
|
||||
dds_entity_unpin (parent_to_delete);
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
dds_entity_final_deinit_before_free (e);
|
||||
dds_free (e);
|
||||
}
|
||||
|
||||
return ret;
|
||||
assert (ret == DDS_RETCODE_OK);
|
||||
(void) ret;
|
||||
return (parent_to_delete != NULL) ? dds_delete_impl_pinned (parent_to_delete, DIS_IMPLICIT) : DDS_RETCODE_OK;
|
||||
}
|
||||
|
||||
bool dds_entity_in_scope (const dds_entity *e, const dds_entity *root)
|
||||
{
|
||||
/* An entity is not an ancestor of itself */
|
||||
while (e != NULL && e != root)
|
||||
e = e->m_parent;
|
||||
return (e != NULL);
|
||||
}
|
||||
|
||||
dds_entity_t dds_get_parent (dds_entity_t entity)
|
||||
{
|
||||
dds_entity *e;
|
||||
dds_return_t rc;
|
||||
if ((rc = dds_entity_lock (entity, DDS_KIND_DONTCARE, &e)) != DDS_RETCODE_OK)
|
||||
if ((rc = dds_entity_pin (entity, &e)) != DDS_RETCODE_OK)
|
||||
return rc;
|
||||
else
|
||||
{
|
||||
dds_entity *parent;
|
||||
dds_entity_t hdl;
|
||||
if ((parent = dds__nonself_parent(e)) == NULL)
|
||||
hdl = DDS_ENTITY_NIL;
|
||||
else
|
||||
{
|
||||
dds_entity *x;
|
||||
hdl = parent->m_hdllink.hdl;
|
||||
if (dds_entity_lock (hdl, DDS_KIND_DONTCARE, &x) == DDS_RETCODE_OK)
|
||||
{
|
||||
parent->m_flags &= ~DDS_ENTITY_IMPLICIT;
|
||||
dds_entity_unlock (parent);
|
||||
}
|
||||
}
|
||||
dds_entity_unlock (e);
|
||||
dds_entity_t hdl = e->m_parent ? e->m_parent->m_hdllink.hdl : 0;
|
||||
dds_entity_unpin (e);
|
||||
return hdl;
|
||||
}
|
||||
}
|
||||
|
||||
dds_participant *dds_entity_participant (dds_entity *e)
|
||||
{
|
||||
while (e && dds_entity_kind (e) != DDS_KIND_PARTICIPANT)
|
||||
e = e->m_parent;
|
||||
return (dds_participant *) e;
|
||||
}
|
||||
|
||||
dds_entity_t dds_get_participant (dds_entity_t entity)
|
||||
{
|
||||
dds_entity *e;
|
||||
dds_return_t rc;
|
||||
if ((rc = dds_entity_lock (entity, DDS_KIND_DONTCARE, &e)) != DDS_RETCODE_OK)
|
||||
if ((rc = dds_entity_pin (entity, &e)) != DDS_RETCODE_OK)
|
||||
return rc;
|
||||
else
|
||||
{
|
||||
dds_entity_t hdl = e->m_participant->m_hdllink.hdl;
|
||||
dds_entity_unlock (e);
|
||||
dds_participant *par = dds_entity_participant (e);
|
||||
dds_entity_t hdl = par ? par->m_entity.m_hdllink.hdl : 0;
|
||||
dds_entity_unpin (e);
|
||||
return hdl;
|
||||
}
|
||||
}
|
||||
|
@ -357,42 +480,28 @@ dds_return_t dds_get_children (dds_entity_t entity, dds_entity_t *children, size
|
|||
dds_entity *e;
|
||||
dds_return_t rc;
|
||||
|
||||
if (children != NULL && (size <= 0 || size >= INT32_MAX))
|
||||
return DDS_RETCODE_BAD_PARAMETER;
|
||||
if (children == NULL && size != 0)
|
||||
if ((children != NULL && (size == 0 || size > INT32_MAX)) || (children == NULL && size != 0))
|
||||
return DDS_RETCODE_BAD_PARAMETER;
|
||||
|
||||
if ((rc = dds_entity_pin (entity, &e)) != DDS_RETCODE_OK)
|
||||
return rc;
|
||||
else
|
||||
{
|
||||
/* FIXME: fix the implicit/explicit stuff so the set_explicit isn't needed; and then this can also be done with a regular iterator & without unlocking */
|
||||
ddsrt_avl_iter_t it;
|
||||
size_t n = 0;
|
||||
dds_instance_handle_t last_iid = 0;
|
||||
struct dds_entity *c;
|
||||
ddsrt_mutex_lock (&e->m_mutex);
|
||||
while ((c = ddsrt_avl_lookup_succ (&dds_entity_children_td, &e->m_children, &last_iid)) != NULL)
|
||||
for (c = ddsrt_avl_iter_first (&dds_entity_children_td, &e->m_children, &it); c != NULL; c = ddsrt_avl_iter_next (&it))
|
||||
{
|
||||
last_iid = c->m_iid;
|
||||
if (n < size)
|
||||
struct dds_entity *tmp;
|
||||
/* Attempt at pinning the entity will fail if it is still pending */
|
||||
if (dds_entity_pin (c->m_hdllink.hdl, &tmp) == DDS_RETCODE_OK)
|
||||
{
|
||||
dds_entity *x;
|
||||
/* Claim child handle to guarantee the child entity remains valid; as we unlock "e" only when we manage to claim the child, and the child has to remain in existence until we release it, "c" remains a valid pointer despite the unlocking. */
|
||||
if (dds_entity_pin (c->m_hdllink.hdl, &x) == DDS_RETCODE_OK)
|
||||
{
|
||||
assert (x == c);
|
||||
if (n < size)
|
||||
children[n] = c->m_hdllink.hdl;
|
||||
ddsrt_mutex_unlock (&e->m_mutex);
|
||||
|
||||
ddsrt_mutex_lock (&c->m_mutex);
|
||||
c->m_flags &= ~DDS_ENTITY_IMPLICIT;
|
||||
ddsrt_mutex_unlock (&c->m_mutex);
|
||||
|
||||
ddsrt_mutex_lock (&e->m_mutex);
|
||||
dds_entity_unpin (c);
|
||||
}
|
||||
n++;
|
||||
dds_entity_unpin (tmp);
|
||||
}
|
||||
n++;
|
||||
}
|
||||
ddsrt_mutex_unlock (&e->m_mutex);
|
||||
dds_entity_unpin (e);
|
||||
|
@ -423,6 +532,8 @@ static uint64_t entity_kind_qos_mask (dds_entity_kind_t kind)
|
|||
case DDS_KIND_COND_QUERY:
|
||||
case DDS_KIND_COND_GUARD:
|
||||
case DDS_KIND_WAITSET:
|
||||
case DDS_KIND_DOMAIN:
|
||||
case DDS_KIND_CYCLONEDDS:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
|
@ -603,7 +714,8 @@ dds_return_t dds_set_qos (dds_entity_t entity, const dds_qos_t *qos)
|
|||
{
|
||||
case DDS_KIND_TOPIC: {
|
||||
dds_entity *pp;
|
||||
if (dds_entity_pin (e->m_participant->m_hdllink.hdl, &pp) == DDS_RETCODE_OK)
|
||||
assert (dds_entity_kind (e->m_parent) == DDS_KIND_PARTICIPANT);
|
||||
if (dds_entity_pin (e->m_parent->m_hdllink.hdl, &pp) == DDS_RETCODE_OK)
|
||||
{
|
||||
pushdown_topic_qos (pp, e);
|
||||
dds_entity_unpin (pp);
|
||||
|
@ -763,7 +875,7 @@ static void pushdown_listener (dds_entity *e)
|
|||
ddsrt_mutex_unlock (&e->m_mutex);
|
||||
|
||||
ddsrt_mutex_lock (&c->m_observers_lock);
|
||||
while (c->m_cb_count > 0)
|
||||
while (c->m_cb_pending_count > 0)
|
||||
ddsrt_cond_wait (&c->m_observers_cond, &c->m_observers_lock);
|
||||
|
||||
ddsrt_mutex_lock (&e->m_observers_lock);
|
||||
|
@ -791,7 +903,7 @@ dds_return_t dds_set_listener (dds_entity_t entity, const dds_listener_t *listen
|
|||
return rc;
|
||||
|
||||
ddsrt_mutex_lock (&e->m_observers_lock);
|
||||
while (e->m_cb_count > 0)
|
||||
while (e->m_cb_pending_count > 0)
|
||||
ddsrt_cond_wait (&e->m_observers_cond, &e->m_observers_lock);
|
||||
|
||||
/* new listener is constructed by combining "listener" with the ancestral listeners;
|
||||
|
@ -801,7 +913,7 @@ dds_return_t dds_set_listener (dds_entity_t entity, const dds_listener_t *listen
|
|||
if (listener)
|
||||
dds_merge_listener (&e->m_listener, listener);
|
||||
x = e;
|
||||
while (dds_entity_kind (x) != DDS_KIND_PARTICIPANT)
|
||||
while (dds_entity_kind (x) != DDS_KIND_CYCLONEDDS)
|
||||
{
|
||||
x = x->m_parent;
|
||||
ddsrt_mutex_lock (&x->m_observers_lock);
|
||||
|
@ -892,17 +1004,26 @@ dds_return_t dds_set_status_mask (dds_entity_t entity, uint32_t mask)
|
|||
if ((mask & ~SAM_STATUS_MASK) != 0)
|
||||
return DDS_RETCODE_BAD_PARAMETER;
|
||||
|
||||
if ((ret = dds_entity_pin (entity, &e)) != DDS_RETCODE_OK)
|
||||
if ((ret = dds_entity_lock (entity, DDS_KIND_DONTCARE, &e)) != DDS_RETCODE_OK)
|
||||
return ret;
|
||||
|
||||
if (dds_handle_is_closed (&e->m_hdllink))
|
||||
{
|
||||
/* The sole reason for locking the mutex was so we can do this atomically with
|
||||
respect to dds_delete (which in turn requires checking whether the handle
|
||||
is still open), because delete relies on the mask to shut down all listener
|
||||
invocations. */
|
||||
dds_entity_unlock (e);
|
||||
return DDS_RETCODE_PRECONDITION_NOT_MET;
|
||||
}
|
||||
|
||||
if ((ret = dds_entity_deriver_validate_status (e, mask)) == DDS_RETCODE_OK)
|
||||
{
|
||||
assert (entity_has_status (e));
|
||||
ddsrt_mutex_lock (&e->m_observers_lock);
|
||||
while (e->m_cb_count > 0)
|
||||
while (e->m_cb_pending_count > 0)
|
||||
ddsrt_cond_wait (&e->m_observers_cond, &e->m_observers_lock);
|
||||
|
||||
/* Don't block internal status triggers. */
|
||||
uint32_t old, new;
|
||||
do {
|
||||
old = ddsrt_atomic_ld32 (&e->m_status.m_status_and_mask);
|
||||
|
@ -910,7 +1031,7 @@ dds_return_t dds_set_status_mask (dds_entity_t entity, uint32_t mask)
|
|||
} while (!ddsrt_atomic_cas32 (&e->m_status.m_status_and_mask, old, new));
|
||||
ddsrt_mutex_unlock (&e->m_observers_lock);
|
||||
}
|
||||
dds_entity_unpin (e);
|
||||
dds_entity_unlock (e);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -946,7 +1067,6 @@ static dds_return_t dds_readtake_status (dds_entity_t entity, uint32_t *status,
|
|||
return ret;
|
||||
}
|
||||
|
||||
|
||||
dds_return_t dds_read_status (dds_entity_t entity, uint32_t *status, uint32_t mask)
|
||||
{
|
||||
return dds_readtake_status (entity, status, mask, false);
|
||||
|
@ -965,11 +1085,11 @@ dds_return_t dds_get_domainid (dds_entity_t entity, dds_domainid_t *id)
|
|||
if (id == NULL)
|
||||
return DDS_RETCODE_BAD_PARAMETER;
|
||||
|
||||
if ((rc = dds_entity_lock (entity, DDS_KIND_DONTCARE, &e)) != DDS_RETCODE_OK)
|
||||
if ((rc = dds_entity_pin (entity, &e)) != DDS_RETCODE_OK)
|
||||
return rc;
|
||||
|
||||
*id = e->m_domain->m_id;
|
||||
dds_entity_unlock(e);
|
||||
*id = e->m_domain ? e->m_domain->m_id : DDS_DOMAIN_DEFAULT;
|
||||
dds_entity_unpin (e);
|
||||
return DDS_RETCODE_OK;
|
||||
}
|
||||
|
||||
|
@ -1029,7 +1149,7 @@ dds_return_t dds_entity_lock (dds_entity_t hdl, dds_entity_kind_t kind, dds_enti
|
|||
void dds_entity_unlock (dds_entity *e)
|
||||
{
|
||||
ddsrt_mutex_unlock (&e->m_mutex);
|
||||
dds_handle_unpin (&e->m_hdllink);
|
||||
dds_entity_unpin (e);
|
||||
}
|
||||
|
||||
dds_return_t dds_triggered (dds_entity_t entity)
|
||||
|
@ -1047,7 +1167,7 @@ dds_return_t dds_triggered (dds_entity_t entity)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static bool in_observer_list_p (const struct dds_entity *observed, const dds_entity *observer)
|
||||
static bool in_observer_list_p (const struct dds_entity *observed, const dds_waitset *observer)
|
||||
{
|
||||
dds_entity_observer *cur;
|
||||
for (cur = observed->m_observers; cur != NULL; cur = cur->m_next)
|
||||
|
@ -1056,13 +1176,15 @@ static bool in_observer_list_p (const struct dds_entity *observed, const dds_ent
|
|||
return false;
|
||||
}
|
||||
|
||||
dds_return_t dds_entity_observer_register (dds_entity *observed, dds_entity *observer, dds_entity_callback cb, dds_entity_delete_callback delete_cb)
|
||||
dds_return_t dds_entity_observer_register (dds_entity *observed, dds_waitset *observer, dds_entity_callback_t cb, dds_entity_attach_callback_t attach_cb, void *attach_arg, dds_entity_delete_callback_t delete_cb)
|
||||
{
|
||||
dds_return_t rc;
|
||||
assert (observed);
|
||||
ddsrt_mutex_lock (&observed->m_observers_lock);
|
||||
if (in_observer_list_p (observed, observer))
|
||||
rc = DDS_RETCODE_PRECONDITION_NOT_MET;
|
||||
else if (!attach_cb (observer, observed, attach_arg))
|
||||
rc = DDS_RETCODE_BAD_PARAMETER;
|
||||
else
|
||||
{
|
||||
dds_entity_observer *o = ddsrt_malloc (sizeof (dds_entity_observer));
|
||||
|
@ -1077,7 +1199,7 @@ dds_return_t dds_entity_observer_register (dds_entity *observed, dds_entity *obs
|
|||
return rc;
|
||||
}
|
||||
|
||||
dds_return_t dds_entity_observer_unregister (dds_entity *observed, dds_entity *observer)
|
||||
dds_return_t dds_entity_observer_unregister (dds_entity *observed, dds_waitset *observer, bool invoke_delete_cb)
|
||||
{
|
||||
dds_return_t rc;
|
||||
dds_entity_observer *prev, *idx;
|
||||
|
@ -1098,6 +1220,8 @@ dds_return_t dds_entity_observer_unregister (dds_entity *observed, dds_entity *o
|
|||
observed->m_observers = idx->m_next;
|
||||
else
|
||||
prev->m_next = idx->m_next;
|
||||
if (invoke_delete_cb)
|
||||
idx->m_delete_cb (idx->m_observer, observed->m_hdllink.hdl);
|
||||
ddsrt_free (idx);
|
||||
rc = DDS_RETCODE_OK;
|
||||
}
|
||||
|
@ -1105,21 +1229,6 @@ dds_return_t dds_entity_observer_unregister (dds_entity *observed, dds_entity *o
|
|||
return rc;
|
||||
}
|
||||
|
||||
static void dds_entity_observers_delete (dds_entity *observed)
|
||||
{
|
||||
dds_entity_observer *idx;
|
||||
ddsrt_mutex_lock (&observed->m_observers_lock);
|
||||
idx = observed->m_observers;
|
||||
while (idx != NULL)
|
||||
{
|
||||
dds_entity_observer *next = idx->m_next;
|
||||
ddsrt_free (idx);
|
||||
idx = next;
|
||||
}
|
||||
observed->m_observers = NULL;
|
||||
ddsrt_mutex_unlock (&observed->m_observers_lock);
|
||||
}
|
||||
|
||||
static void dds_entity_observers_signal (dds_entity *observed, uint32_t status)
|
||||
{
|
||||
for (dds_entity_observer *idx = observed->m_observers; idx; idx = idx->m_next)
|
||||
|
@ -1128,8 +1237,16 @@ static void dds_entity_observers_signal (dds_entity *observed, uint32_t status)
|
|||
|
||||
static void dds_entity_observers_signal_delete (dds_entity *observed)
|
||||
{
|
||||
for (dds_entity_observer *idx = observed->m_observers; idx; idx = idx->m_next)
|
||||
dds_entity_observer *idx;
|
||||
idx = observed->m_observers;
|
||||
while (idx != NULL)
|
||||
{
|
||||
dds_entity_observer *next = idx->m_next;
|
||||
idx->m_delete_cb (idx->m_observer, observed->m_hdllink.hdl);
|
||||
ddsrt_free (idx);
|
||||
idx = next;
|
||||
}
|
||||
observed->m_observers = NULL;
|
||||
}
|
||||
|
||||
void dds_entity_status_signal (dds_entity *e, uint32_t status)
|
||||
|
@ -1158,11 +1275,13 @@ void dds_entity_trigger_set (dds_entity *e, uint32_t t)
|
|||
{
|
||||
assert (! entity_has_status (e));
|
||||
uint32_t oldst;
|
||||
ddsrt_mutex_lock (&e->m_observers_lock);
|
||||
do {
|
||||
oldst = ddsrt_atomic_ld32 (&e->m_status.m_trigger);
|
||||
} while (!ddsrt_atomic_cas32 (&e->m_status.m_trigger, oldst, t));
|
||||
if (oldst == 0 && t != 0)
|
||||
dds_entity_observers_signal (e, t);
|
||||
ddsrt_mutex_unlock (&e->m_observers_lock);
|
||||
}
|
||||
|
||||
dds_entity_t dds_get_topic (dds_entity_t entity)
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
*/
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "dds__init.h"
|
||||
#include "dds__reader.h"
|
||||
#include "dds__guardcond.h"
|
||||
#include "dds__participant.h"
|
||||
|
@ -22,28 +23,53 @@
|
|||
DECL_ENTITY_LOCK_UNLOCK (extern inline, dds_guardcond)
|
||||
|
||||
const struct dds_entity_deriver dds_entity_deriver_guardcondition = {
|
||||
.interrupt = dds_entity_deriver_dummy_interrupt,
|
||||
.close = dds_entity_deriver_dummy_close,
|
||||
.delete = dds_entity_deriver_dummy_delete,
|
||||
.set_qos = dds_entity_deriver_dummy_set_qos,
|
||||
.validate_status = dds_entity_deriver_dummy_validate_status
|
||||
};
|
||||
|
||||
dds_entity_t dds_create_guardcondition (dds_entity_t participant)
|
||||
dds_entity_t dds_create_guardcondition (dds_entity_t owner)
|
||||
{
|
||||
dds_participant *pp;
|
||||
dds_entity *e;
|
||||
dds_return_t rc;
|
||||
|
||||
if ((rc = dds_participant_lock (participant, &pp)) != DDS_RETCODE_OK)
|
||||
/* If the owner is any ordinary (allowed) entity, the library is already initialised and calling
|
||||
init here is cheap. If it is DDS_CYCLONEDDS_HANDLE, we may have to initialise the library, so
|
||||
have to call it. If it is some bogus value and the library is not initialised yet ... so be
|
||||
it. Naturally, this requires us to call delete on DDS_CYCLONEDDS_HANDLE afterward. */
|
||||
if ((rc = dds_init ()) < 0)
|
||||
return rc;
|
||||
else
|
||||
|
||||
if ((rc = dds_entity_lock (owner, DDS_KIND_DONTCARE, &e)) != DDS_RETCODE_OK)
|
||||
goto err_entity_lock;
|
||||
|
||||
switch (dds_entity_kind (e))
|
||||
{
|
||||
dds_guardcond *gcond = dds_alloc (sizeof (*gcond));
|
||||
dds_entity_t hdl = dds_entity_init (&gcond->m_entity, &pp->m_entity, DDS_KIND_COND_GUARD, NULL, NULL, 0);
|
||||
gcond->m_entity.m_iid = ddsi_iid_gen ();
|
||||
dds_entity_register_child (&pp->m_entity, &gcond->m_entity);
|
||||
dds_participant_unlock (pp);
|
||||
return hdl;
|
||||
case DDS_KIND_CYCLONEDDS:
|
||||
case DDS_KIND_DOMAIN:
|
||||
case DDS_KIND_PARTICIPANT:
|
||||
break;
|
||||
default:
|
||||
rc = DDS_RETCODE_ILLEGAL_OPERATION;
|
||||
goto err_entity_kind;
|
||||
}
|
||||
|
||||
dds_guardcond *gcond = dds_alloc (sizeof (*gcond));
|
||||
dds_entity_t hdl = dds_entity_init (&gcond->m_entity, e, DDS_KIND_COND_GUARD, NULL, NULL, 0);
|
||||
gcond->m_entity.m_iid = ddsi_iid_gen ();
|
||||
dds_entity_register_child (e, &gcond->m_entity);
|
||||
dds_entity_init_complete (&gcond->m_entity);
|
||||
dds_entity_unlock (e);
|
||||
dds_delete_impl_pinned (&dds_global.m_entity, DIS_EXPLICIT);
|
||||
return hdl;
|
||||
|
||||
err_entity_kind:
|
||||
dds_entity_unlock (e);
|
||||
err_entity_lock:
|
||||
dds_delete_impl_pinned (&dds_global.m_entity, DIS_EXPLICIT);
|
||||
return rc;
|
||||
}
|
||||
|
||||
dds_return_t dds_set_guardcondition (dds_entity_t condition, bool triggered)
|
||||
|
|
|
@ -20,27 +20,10 @@
|
|||
#include "dds__handles.h"
|
||||
#include "dds__types.h"
|
||||
|
||||
/* FIXME: this code isn't really correct when USE_CHH is set:
|
||||
- the DDS entity code doesn't really play by the awake/asleep mechanism
|
||||
- there is no provision in the code for a handle being deleted concurrent to a lookup,
|
||||
that is, deleting handle links should also go through the GC
|
||||
entity framework needs a fair bit of rewriting anyway ... */
|
||||
#define USE_CHH 0
|
||||
|
||||
#define HDL_FLAG_CLOSED (0x80000000u)
|
||||
|
||||
/* ref count: # outstanding references to this handle/object (not so sure it is
|
||||
ideal to have a one-to-one mapping between the two, but that is what the rest
|
||||
of the code assumes at the moment); so this limits one to having, e.g., no
|
||||
more than 64k endpoints referencing the same topic */
|
||||
#define HDL_REFCOUNT_MASK (0x0ffff000u)
|
||||
#define HDL_REFCOUNT_UNIT (0x00001000u)
|
||||
#define HDL_REFCOUNT_SHIFT 12
|
||||
|
||||
/* pin count: # concurrent operations, so allowing up to 4096 threads had better
|
||||
be enough ... */
|
||||
#define HDL_PINCOUNT_MASK (0x00000fffu)
|
||||
#define HDL_PINCOUNT_UNIT (0x00000001u)
|
||||
|
||||
/* Maximum number of handles is INT32_MAX - 1, but as the allocator relies on a
|
||||
random generator for finding a free one, the time spent in the dds_handle_create
|
||||
|
@ -50,11 +33,7 @@
|
|||
#define MAX_HANDLES (INT32_MAX / 128)
|
||||
|
||||
struct dds_handle_server {
|
||||
#if USE_CHH
|
||||
struct ddsrt_chh *ht;
|
||||
#else
|
||||
struct ddsrt_hh *ht;
|
||||
#endif
|
||||
size_t count;
|
||||
ddsrt_mutex_t lock;
|
||||
ddsrt_cond_t cond;
|
||||
|
@ -78,45 +57,46 @@ static int handle_equal (const void *va, const void *vb)
|
|||
|
||||
dds_return_t dds_handle_server_init (void)
|
||||
{
|
||||
#if USE_CHH
|
||||
handles.ht = ddsrt_chh_new (128, handle_hash, handle_equal, free_via_gc);
|
||||
#else
|
||||
handles.ht = ddsrt_hh_new (128, handle_hash, handle_equal);
|
||||
#endif
|
||||
handles.count = 0;
|
||||
ddsrt_mutex_init (&handles.lock);
|
||||
ddsrt_cond_init (&handles.cond);
|
||||
/* called with ddsrt's singleton mutex held (see dds_init/fini) */
|
||||
if (handles.ht == NULL)
|
||||
{
|
||||
handles.ht = ddsrt_hh_new (128, handle_hash, handle_equal);
|
||||
handles.count = 0;
|
||||
ddsrt_mutex_init (&handles.lock);
|
||||
ddsrt_cond_init (&handles.cond);
|
||||
}
|
||||
return DDS_RETCODE_OK;
|
||||
}
|
||||
|
||||
void dds_handle_server_fini (void)
|
||||
{
|
||||
#if USE_CHH
|
||||
/* called with ddsrt's singleton mutex held (see dds_init/fini) */
|
||||
if (handles.ht != NULL)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
struct ddsrt_chh_iter it;
|
||||
assert (ddsrt_chh_iter_first (handles.ht, &it) == NULL);
|
||||
struct ddsrt_hh_iter it;
|
||||
for (struct dds_handle_link *link = ddsrt_hh_iter_first (handles.ht, &it); link != NULL; link = ddsrt_hh_iter_next (&it))
|
||||
{
|
||||
uint32_t cf = ddsrt_atomic_ld32 (&link->cnt_flags);
|
||||
DDS_ERROR ("handle %"PRId32" pin %"PRIu32" refc %"PRIu32"%s%s%s\n", link->hdl,
|
||||
cf & HDL_PINCOUNT_MASK, (cf & HDL_REFCOUNT_MASK) >> HDL_REFCOUNT_SHIFT,
|
||||
cf & HDL_FLAG_PENDING ? " pending" : "",
|
||||
cf & HDL_FLAG_CLOSING ? " closing" : "",
|
||||
cf & HDL_FLAG_CLOSED ? " closed" : "");
|
||||
}
|
||||
assert (ddsrt_hh_iter_first (handles.ht, &it) == NULL);
|
||||
#endif
|
||||
ddsrt_chh_free (handles.ht);
|
||||
#else /* USE_CHH */
|
||||
#ifndef NDEBUG
|
||||
struct ddsrt_hh_iter it;
|
||||
assert (ddsrt_hh_iter_first (handles.ht, &it) == NULL);
|
||||
#endif
|
||||
ddsrt_hh_free (handles.ht);
|
||||
#endif /* USE_CHH */
|
||||
ddsrt_cond_destroy (&handles.cond);
|
||||
ddsrt_mutex_destroy (&handles.lock);
|
||||
handles.ht = NULL;
|
||||
ddsrt_hh_free (handles.ht);
|
||||
ddsrt_cond_destroy (&handles.cond);
|
||||
ddsrt_mutex_destroy (&handles.lock);
|
||||
handles.ht = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#if USE_CHH
|
||||
static bool hhadd (struct ddsrt_chh *ht, void *elem) { return ddsrt_chh_add (ht, elem); }
|
||||
#else
|
||||
static bool hhadd (struct ddsrt_hh *ht, void *elem) { return ddsrt_hh_add (ht, elem); }
|
||||
#endif
|
||||
static dds_handle_t dds_handle_create_int (struct dds_handle_link *link)
|
||||
{
|
||||
ddsrt_atomic_st32 (&link->cnt_flags, HDL_REFCOUNT_UNIT);
|
||||
ddsrt_atomic_st32 (&link->cnt_flags, HDL_FLAG_PENDING | HDL_REFCOUNT_UNIT | 1u);
|
||||
do {
|
||||
do {
|
||||
link->hdl = (int32_t) (ddsrt_random () & INT32_MAX);
|
||||
|
@ -127,13 +107,7 @@ static dds_handle_t dds_handle_create_int (struct dds_handle_link *link)
|
|||
|
||||
dds_handle_t dds_handle_create (struct dds_handle_link *link)
|
||||
{
|
||||
#if USE_CHH
|
||||
struct thread_state1 * const ts1 = lookup_thread_state ();
|
||||
#endif
|
||||
dds_handle_t ret;
|
||||
#if USE_CHH
|
||||
thread_state_awake (ts1);
|
||||
#endif
|
||||
ddsrt_mutex_lock (&handles.lock);
|
||||
if (handles.count == MAX_HANDLES)
|
||||
{
|
||||
|
@ -143,55 +117,67 @@ dds_handle_t dds_handle_create (struct dds_handle_link *link)
|
|||
else
|
||||
{
|
||||
handles.count++;
|
||||
#if USE_CHH
|
||||
ddsrt_mutex_unlock (&handles.lock);
|
||||
ret = dds_handle_create_int (link);
|
||||
#else
|
||||
ret = dds_handle_create_int (link);
|
||||
ddsrt_mutex_unlock (&handles.lock);
|
||||
#endif
|
||||
assert (ret > 0);
|
||||
}
|
||||
#if USE_CHH
|
||||
thread_state_asleep (ts1);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
void dds_handle_close (struct dds_handle_link *link)
|
||||
dds_return_t dds_handle_register_special (struct dds_handle_link *link, dds_handle_t handle)
|
||||
{
|
||||
ddsrt_atomic_or32 (&link->cnt_flags, HDL_FLAG_CLOSED);
|
||||
dds_return_t ret;
|
||||
if (handle <= 0)
|
||||
return DDS_RETCODE_BAD_PARAMETER;
|
||||
ddsrt_mutex_lock (&handles.lock);
|
||||
if (handles.count == MAX_HANDLES)
|
||||
{
|
||||
ddsrt_mutex_unlock (&handles.lock);
|
||||
ret = DDS_RETCODE_OUT_OF_RESOURCES;
|
||||
}
|
||||
else
|
||||
{
|
||||
handles.count++;
|
||||
ddsrt_atomic_st32 (&link->cnt_flags, HDL_FLAG_PENDING | HDL_REFCOUNT_UNIT | 1u);
|
||||
link->hdl = handle;
|
||||
if (hhadd (handles.ht, link))
|
||||
ret = handle;
|
||||
else
|
||||
ret = DDS_RETCODE_BAD_PARAMETER;
|
||||
ddsrt_mutex_unlock (&handles.lock);
|
||||
assert (ret > 0);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int32_t dds_handle_delete (struct dds_handle_link *link, dds_duration_t timeout)
|
||||
void dds_handle_unpend (struct dds_handle_link *link)
|
||||
{
|
||||
#if USE_CHH
|
||||
struct thread_state1 * const ts1 = lookup_thread_state ();
|
||||
#ifndef NDEBUG
|
||||
uint32_t cf = ddsrt_atomic_ld32 (&link->cnt_flags);
|
||||
assert ((cf & HDL_FLAG_PENDING));
|
||||
assert (!(cf & HDL_FLAG_CLOSED));
|
||||
assert (!(cf & HDL_FLAG_CLOSING));
|
||||
assert ((cf & HDL_REFCOUNT_MASK) >= HDL_REFCOUNT_UNIT);
|
||||
assert ((cf & HDL_PINCOUNT_MASK) >= 1u);
|
||||
#endif
|
||||
assert (ddsrt_atomic_ld32 (&link->cnt_flags) & HDL_FLAG_CLOSED);
|
||||
ddsrt_mutex_lock (&handles.lock);
|
||||
if ((ddsrt_atomic_ld32 (&link->cnt_flags) & HDL_PINCOUNT_MASK) != 0)
|
||||
ddsrt_atomic_and32 (&link->cnt_flags, ~HDL_FLAG_PENDING);
|
||||
dds_handle_unpin (link);
|
||||
}
|
||||
|
||||
int32_t dds_handle_delete (struct dds_handle_link *link)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
uint32_t cf = ddsrt_atomic_ld32 (&link->cnt_flags);
|
||||
if (!(cf & HDL_FLAG_PENDING))
|
||||
{
|
||||
/* FIXME: there is no sensible solution when this times out, so it must
|
||||
never do that ... */
|
||||
const dds_time_t abstimeout = dds_time () + timeout;
|
||||
while ((ddsrt_atomic_ld32 (&link->cnt_flags) & HDL_PINCOUNT_MASK) != 0)
|
||||
{
|
||||
if (!ddsrt_cond_waituntil (&handles.cond, &handles.lock, abstimeout))
|
||||
{
|
||||
ddsrt_mutex_unlock (&handles.lock);
|
||||
fprintf (stderr, "** timeout in handle_delete **\n");
|
||||
return DDS_RETCODE_TIMEOUT;
|
||||
}
|
||||
}
|
||||
assert (cf & HDL_FLAG_CLOSING);
|
||||
assert (cf & HDL_FLAG_CLOSED);
|
||||
assert ((cf & HDL_REFCOUNT_MASK) == 0u);
|
||||
}
|
||||
#if USE_CHH
|
||||
thread_state_awake (ts1);
|
||||
int x = ddsrt_chh_remove (handles.ht, link);
|
||||
thread_state_asleep (ts1);
|
||||
#else
|
||||
int x = ddsrt_hh_remove (handles.ht, link);
|
||||
assert ((cf & HDL_PINCOUNT_MASK) == 1u);
|
||||
#endif
|
||||
ddsrt_mutex_lock (&handles.lock);
|
||||
int x = ddsrt_hh_remove (handles.ht, link);
|
||||
assert(x);
|
||||
(void)x;
|
||||
assert (handles.count > 0);
|
||||
|
@ -200,11 +186,8 @@ int32_t dds_handle_delete (struct dds_handle_link *link, dds_duration_t timeout)
|
|||
return DDS_RETCODE_OK;
|
||||
}
|
||||
|
||||
int32_t dds_handle_pin (dds_handle_t hdl, struct dds_handle_link **link)
|
||||
static int32_t dds_handle_pin_int (dds_handle_t hdl, uint32_t delta, struct dds_handle_link **link)
|
||||
{
|
||||
#if USE_CHH
|
||||
struct thread_state1 * const ts1 = lookup_thread_state ();
|
||||
#endif
|
||||
struct dds_handle_link dummy = { .hdl = hdl };
|
||||
int32_t rc;
|
||||
/* it makes sense to check here for initialization: the first thing any operation
|
||||
|
@ -218,41 +201,41 @@ int32_t dds_handle_pin (dds_handle_t hdl, struct dds_handle_link **link)
|
|||
if (handles.ht == NULL)
|
||||
return DDS_RETCODE_PRECONDITION_NOT_MET;
|
||||
|
||||
#if USE_CHH
|
||||
thread_state_awake (ts1);
|
||||
*link = ddsrt_chh_lookup (handles.ht, &dummy);
|
||||
#else
|
||||
ddsrt_mutex_lock (&handles.lock);
|
||||
*link = ddsrt_hh_lookup (handles.ht, &dummy);
|
||||
#endif
|
||||
if (*link == NULL)
|
||||
rc = DDS_RETCODE_BAD_PARAMETER;
|
||||
else
|
||||
{
|
||||
uint32_t cnt_flags;
|
||||
uint32_t cf;
|
||||
/* Assume success; bail out if the object turns out to be in the process of
|
||||
being deleted */
|
||||
rc = DDS_RETCODE_OK;
|
||||
do {
|
||||
cnt_flags = ddsrt_atomic_ld32 (&(*link)->cnt_flags);
|
||||
if (cnt_flags & HDL_FLAG_CLOSED)
|
||||
cf = ddsrt_atomic_ld32 (&(*link)->cnt_flags);
|
||||
if (cf & (HDL_FLAG_CLOSED | HDL_FLAG_CLOSING | HDL_FLAG_PENDING))
|
||||
{
|
||||
rc = DDS_RETCODE_BAD_PARAMETER;
|
||||
break;
|
||||
}
|
||||
} while (!ddsrt_atomic_cas32 (&(*link)->cnt_flags, cnt_flags, cnt_flags + HDL_PINCOUNT_UNIT));
|
||||
} while (!ddsrt_atomic_cas32 (&(*link)->cnt_flags, cf, cf + delta));
|
||||
}
|
||||
#if USE_CHH
|
||||
thread_state_asleep (ts1);
|
||||
#else
|
||||
ddsrt_mutex_unlock (&handles.lock);
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
|
||||
int32_t dds_handle_pin (dds_handle_t hdl, struct dds_handle_link **link)
|
||||
{
|
||||
return dds_handle_pin_int (hdl, 1u, link);
|
||||
}
|
||||
|
||||
int32_t dds_handle_pin_and_ref (dds_handle_t hdl, struct dds_handle_link **link)
|
||||
{
|
||||
return dds_handle_pin_int (hdl, HDL_REFCOUNT_UNIT + 1u, link);
|
||||
}
|
||||
|
||||
void dds_handle_repin (struct dds_handle_link *link)
|
||||
{
|
||||
DDSRT_STATIC_ASSERT (HDL_PINCOUNT_UNIT == 1);
|
||||
uint32_t x = ddsrt_atomic_inc32_nv (&link->cnt_flags);
|
||||
assert (!(x & HDL_FLAG_CLOSED));
|
||||
(void) x;
|
||||
|
@ -260,13 +243,20 @@ void dds_handle_repin (struct dds_handle_link *link)
|
|||
|
||||
void dds_handle_unpin (struct dds_handle_link *link)
|
||||
{
|
||||
DDSRT_STATIC_ASSERT (HDL_PINCOUNT_UNIT == 1);
|
||||
if ((ddsrt_atomic_dec32_ov (&link->cnt_flags) & (HDL_FLAG_CLOSED | HDL_PINCOUNT_MASK)) == (HDL_FLAG_CLOSED | HDL_PINCOUNT_UNIT))
|
||||
#ifndef NDEBUG
|
||||
uint32_t cf = ddsrt_atomic_ld32 (&link->cnt_flags);
|
||||
assert (!(cf & HDL_FLAG_CLOSED));
|
||||
if (cf & HDL_FLAG_CLOSING)
|
||||
assert ((cf & HDL_PINCOUNT_MASK) > 1u);
|
||||
else
|
||||
assert ((cf & HDL_PINCOUNT_MASK) >= 1u);
|
||||
#endif
|
||||
ddsrt_mutex_lock (&handles.lock);
|
||||
if ((ddsrt_atomic_dec32_nv (&link->cnt_flags) & (HDL_FLAG_CLOSING | HDL_PINCOUNT_MASK)) == (HDL_FLAG_CLOSING | 1u))
|
||||
{
|
||||
ddsrt_mutex_lock (&handles.lock);
|
||||
ddsrt_cond_broadcast (&handles.cond);
|
||||
ddsrt_mutex_unlock (&handles.lock);
|
||||
}
|
||||
ddsrt_mutex_unlock (&handles.lock);
|
||||
}
|
||||
|
||||
void dds_handle_add_ref (struct dds_handle_link *link)
|
||||
|
@ -283,12 +273,27 @@ bool dds_handle_drop_ref (struct dds_handle_link *link)
|
|||
if ((old & HDL_REFCOUNT_MASK) != HDL_REFCOUNT_UNIT)
|
||||
new = old - HDL_REFCOUNT_UNIT;
|
||||
else
|
||||
new = (old - HDL_REFCOUNT_UNIT) | HDL_FLAG_CLOSED;
|
||||
new = (old - HDL_REFCOUNT_UNIT) | HDL_FLAG_CLOSING;
|
||||
} while (!ddsrt_atomic_cas32 (&link->cnt_flags, old, new));
|
||||
return (new & HDL_REFCOUNT_MASK) == 0;
|
||||
}
|
||||
|
||||
bool dds_handle_is_closed (struct dds_handle_link *link)
|
||||
void dds_handle_close_wait (struct dds_handle_link *link)
|
||||
{
|
||||
return (ddsrt_atomic_ld32 (&link->cnt_flags) & HDL_FLAG_CLOSED) != 0;
|
||||
#ifndef NDEBUG
|
||||
uint32_t cf = ddsrt_atomic_ld32 (&link->cnt_flags);
|
||||
assert ((cf & HDL_FLAG_CLOSING));
|
||||
assert (!(cf & HDL_FLAG_CLOSED));
|
||||
assert ((cf & HDL_REFCOUNT_MASK) == 0u);
|
||||
assert ((cf & HDL_PINCOUNT_MASK) >= 1u);
|
||||
#endif
|
||||
ddsrt_mutex_lock (&handles.lock);
|
||||
while ((ddsrt_atomic_ld32 (&link->cnt_flags) & HDL_PINCOUNT_MASK) != 1u)
|
||||
ddsrt_cond_wait (&handles.cond, &handles.lock);
|
||||
/* only one thread may call close_wait on a given handle */
|
||||
assert (!(ddsrt_atomic_ld32 (&link->cnt_flags) & HDL_FLAG_CLOSED));
|
||||
ddsrt_atomic_or32 (&link->cnt_flags, HDL_FLAG_CLOSED);
|
||||
ddsrt_mutex_unlock (&handles.lock);
|
||||
}
|
||||
|
||||
extern inline bool dds_handle_is_closed (struct dds_handle_link *link);
|
||||
|
|
|
@ -18,10 +18,11 @@
|
|||
#include "dds/ddsrt/process.h"
|
||||
#include "dds/ddsrt/heap.h"
|
||||
#include "dds__init.h"
|
||||
#include "dds__rhc.h"
|
||||
#include "dds/ddsc/dds_rhc.h"
|
||||
#include "dds__domain.h"
|
||||
#include "dds__builtin.h"
|
||||
#include "dds__whc_builtintopic.h"
|
||||
#include "dds__entity.h"
|
||||
#include "dds/ddsi/ddsi_iid.h"
|
||||
#include "dds/ddsi/ddsi_tkmap.h"
|
||||
#include "dds/ddsi/ddsi_serdata.h"
|
||||
|
@ -32,10 +33,49 @@
|
|||
#include "dds/ddsi/q_globals.h"
|
||||
#include "dds/version.h"
|
||||
|
||||
#define DOMAIN_ID_MIN 0
|
||||
#define DOMAIN_ID_MAX 230
|
||||
static void dds_close (struct dds_entity *e);
|
||||
static dds_return_t dds_fini (struct dds_entity *e);
|
||||
|
||||
dds_globals dds_global;
|
||||
const struct dds_entity_deriver dds_entity_deriver_cyclonedds = {
|
||||
.interrupt = dds_entity_deriver_dummy_interrupt,
|
||||
.close = dds_close,
|
||||
.delete = dds_fini,
|
||||
.set_qos = dds_entity_deriver_dummy_set_qos,
|
||||
.validate_status = dds_entity_deriver_dummy_validate_status
|
||||
};
|
||||
|
||||
dds_cyclonedds_entity dds_global;
|
||||
|
||||
#define CDDS_STATE_ZERO 0u
|
||||
#define CDDS_STATE_STARTING 1u
|
||||
#define CDDS_STATE_READY 2u
|
||||
#define CDDS_STATE_STOPPING 3u
|
||||
static ddsrt_atomic_uint32_t dds_state = DDSRT_ATOMIC_UINT32_INIT (CDDS_STATE_ZERO);
|
||||
|
||||
static void common_cleanup (void)
|
||||
{
|
||||
if (thread_states_fini ())
|
||||
dds_handle_server_fini ();
|
||||
|
||||
ddsi_iid_fini ();
|
||||
ddsrt_cond_destroy (&dds_global.m_cond);
|
||||
ddsrt_mutex_destroy (&dds_global.m_mutex);
|
||||
|
||||
ddsrt_atomic_st32 (&dds_state, CDDS_STATE_ZERO);
|
||||
ddsrt_cond_broadcast (ddsrt_get_singleton_cond ());
|
||||
}
|
||||
|
||||
static bool cyclonedds_entity_ready (uint32_t s)
|
||||
{
|
||||
assert (s != CDDS_STATE_ZERO);
|
||||
if (s == CDDS_STATE_STARTING || s == CDDS_STATE_STOPPING)
|
||||
return false;
|
||||
else
|
||||
{
|
||||
struct dds_handle_link *x;
|
||||
return dds_handle_pin_and_ref (DDS_CYCLONEDDS_HANDLE, &x) == DDS_RETCODE_OK;
|
||||
}
|
||||
}
|
||||
|
||||
dds_return_t dds_init (void)
|
||||
{
|
||||
|
@ -43,18 +83,34 @@ dds_return_t dds_init (void)
|
|||
|
||||
ddsrt_init ();
|
||||
ddsrt_mutex_t * const init_mutex = ddsrt_get_singleton_mutex ();
|
||||
ddsrt_cond_t * const init_cond = ddsrt_get_singleton_cond ();
|
||||
|
||||
ddsrt_mutex_lock (init_mutex);
|
||||
if (dds_global.m_init_count++ != 0)
|
||||
uint32_t s = ddsrt_atomic_ld32 (&dds_state);
|
||||
while (s != CDDS_STATE_ZERO && !cyclonedds_entity_ready (s))
|
||||
{
|
||||
ddsrt_mutex_unlock (init_mutex);
|
||||
return DDS_RETCODE_OK;
|
||||
ddsrt_cond_wait (init_cond, init_mutex);
|
||||
s = ddsrt_atomic_ld32 (&dds_state);
|
||||
}
|
||||
switch (s)
|
||||
{
|
||||
case CDDS_STATE_READY:
|
||||
assert (dds_global.m_entity.m_hdllink.hdl == DDS_CYCLONEDDS_HANDLE);
|
||||
ddsrt_mutex_unlock (init_mutex);
|
||||
return DDS_RETCODE_OK;
|
||||
case CDDS_STATE_ZERO:
|
||||
ddsrt_atomic_st32 (&dds_state, CDDS_STATE_STARTING);
|
||||
break;
|
||||
default:
|
||||
ddsrt_mutex_unlock (init_mutex);
|
||||
ddsrt_fini ();
|
||||
return DDS_RETCODE_ERROR;
|
||||
}
|
||||
|
||||
ddsrt_mutex_init (&dds_global.m_mutex);
|
||||
ddsrt_cond_init (&dds_global.m_cond);
|
||||
ddsi_iid_init ();
|
||||
thread_states_init_static ();
|
||||
thread_states_init (64);
|
||||
upgrade_main_thread ();
|
||||
|
||||
if (dds_handle_server_init () != DDS_RETCODE_OK)
|
||||
{
|
||||
|
@ -63,30 +119,48 @@ dds_return_t dds_init (void)
|
|||
goto fail_handleserver;
|
||||
}
|
||||
|
||||
dds_entity_init (&dds_global.m_entity, NULL, DDS_KIND_CYCLONEDDS, NULL, NULL, 0);
|
||||
dds_global.m_entity.m_iid = ddsi_iid_gen ();
|
||||
dds_global.m_entity.m_flags = DDS_ENTITY_IMPLICIT;
|
||||
dds_handle_repin (&dds_global.m_entity.m_hdllink);
|
||||
dds_entity_add_ref_locked (&dds_global.m_entity);
|
||||
dds_entity_init_complete (&dds_global.m_entity);
|
||||
ddsrt_atomic_st32 (&dds_state, CDDS_STATE_READY);
|
||||
ddsrt_mutex_unlock (init_mutex);
|
||||
return DDS_RETCODE_OK;
|
||||
|
||||
fail_handleserver:
|
||||
ddsrt_mutex_destroy (&dds_global.m_mutex);
|
||||
dds_global.m_init_count--;
|
||||
common_cleanup ();
|
||||
ddsrt_mutex_unlock (init_mutex);
|
||||
ddsrt_fini ();
|
||||
return ret;
|
||||
}
|
||||
|
||||
extern void dds_fini (void)
|
||||
static void dds_close (struct dds_entity *e)
|
||||
{
|
||||
(void) e;
|
||||
assert (ddsrt_atomic_ld32 (&dds_state) == CDDS_STATE_READY);
|
||||
ddsrt_atomic_st32 (&dds_state, CDDS_STATE_STOPPING);
|
||||
}
|
||||
|
||||
static dds_return_t dds_fini (struct dds_entity *e)
|
||||
{
|
||||
(void) e;
|
||||
ddsrt_mutex_t * const init_mutex = ddsrt_get_singleton_mutex ();
|
||||
/* If there are multiple domains shutting down simultaneously, the one "deleting" the top-level
|
||||
entity (and thus arriving here) may have overtaken another thread that is still in the process
|
||||
of deleting its domain object. For most entities such races are not an issue, but here we tear
|
||||
down the run-time, so here we must wait until everyone else is out. */
|
||||
ddsrt_mutex_lock (&dds_global.m_mutex);
|
||||
while (!ddsrt_avl_is_empty (&dds_global.m_domains))
|
||||
ddsrt_cond_wait (&dds_global.m_cond, &dds_global.m_mutex);
|
||||
ddsrt_mutex_unlock (&dds_global.m_mutex);
|
||||
|
||||
ddsrt_mutex_lock (init_mutex);
|
||||
assert (dds_global.m_init_count > 0);
|
||||
if (--dds_global.m_init_count == 0)
|
||||
{
|
||||
dds_handle_server_fini ();
|
||||
downgrade_main_thread ();
|
||||
thread_states_fini ();
|
||||
ddsi_iid_fini ();
|
||||
ddsrt_mutex_destroy (&dds_global.m_mutex);
|
||||
}
|
||||
assert (ddsrt_atomic_ld32 (&dds_state) == CDDS_STATE_STOPPING);
|
||||
dds_entity_final_deinit_before_free (e);
|
||||
common_cleanup ();
|
||||
ddsrt_mutex_unlock (init_mutex);
|
||||
ddsrt_fini ();
|
||||
return DDS_RETCODE_NO_DATA;
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#include "dds__entity.h"
|
||||
#include "dds__write.h"
|
||||
#include "dds__writer.h"
|
||||
#include "dds__rhc.h"
|
||||
#include "dds/ddsc/dds_rhc.h"
|
||||
#include "dds/ddsi/ddsi_tkmap.h"
|
||||
#include "dds/ddsi/ddsi_serdata.h"
|
||||
#include "dds/ddsi/q_entity.h"
|
||||
|
|
|
@ -27,15 +27,14 @@ dds_return_t dds_get_matched_subscriptions (dds_entity_t writer, dds_instance_ha
|
|||
{
|
||||
dds_writer *wr;
|
||||
dds_return_t rc;
|
||||
if (rds == NULL && nrds > 0)
|
||||
if ((rds != NULL && (nrds == 0 || nrds > INT32_MAX)) || (rds == NULL && nrds != 0))
|
||||
return DDS_RETCODE_BAD_PARAMETER;
|
||||
if ((rc = dds_writer_lock (writer, &wr)) != DDS_RETCODE_OK)
|
||||
return rc;
|
||||
else
|
||||
{
|
||||
const struct ephash *gh = wr->m_entity.m_domain->gv.guid_hash;
|
||||
const int32_t nrds_max = (nrds > INT32_MAX) ? INT32_MAX : (int32_t) nrds;
|
||||
int32_t nrds_act = 0;
|
||||
size_t nrds_act = 0;
|
||||
ddsrt_avl_iter_t it;
|
||||
/* FIXME: this ought not be so tightly coupled to the lower layer */
|
||||
thread_state_awake (lookup_thread_state (), &wr->m_entity.m_domain->gv);
|
||||
|
@ -47,7 +46,7 @@ dds_return_t dds_get_matched_subscriptions (dds_entity_t writer, dds_instance_ha
|
|||
struct proxy_reader *prd;
|
||||
if ((prd = ephash_lookup_proxy_reader_guid (gh, &m->prd_guid)) != NULL)
|
||||
{
|
||||
if (nrds_act < nrds_max)
|
||||
if (nrds_act < nrds)
|
||||
rds[nrds_act] = prd->e.iid;
|
||||
nrds_act++;
|
||||
}
|
||||
|
@ -59,7 +58,7 @@ dds_return_t dds_get_matched_subscriptions (dds_entity_t writer, dds_instance_ha
|
|||
struct reader *rd;
|
||||
if ((rd = ephash_lookup_reader_guid (gh, &m->rd_guid)) != NULL)
|
||||
{
|
||||
if (nrds_act < nrds_max)
|
||||
if (nrds_act < nrds)
|
||||
rds[nrds_act] = rd->e.iid;
|
||||
nrds_act++;
|
||||
}
|
||||
|
@ -67,7 +66,10 @@ dds_return_t dds_get_matched_subscriptions (dds_entity_t writer, dds_instance_ha
|
|||
ddsrt_mutex_unlock (&wr->m_wr->e.lock);
|
||||
thread_state_asleep (lookup_thread_state ());
|
||||
dds_writer_unlock (wr);
|
||||
return nrds_act;
|
||||
/* FIXME: is it really true that there can not be more than INT32_MAX matching readers?
|
||||
(in practice it'll come to a halt long before that) */
|
||||
assert (nrds_act <= INT32_MAX);
|
||||
return (dds_return_t) nrds_act;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,15 +77,14 @@ dds_return_t dds_get_matched_publications (dds_entity_t reader, dds_instance_han
|
|||
{
|
||||
dds_reader *rd;
|
||||
dds_return_t rc;
|
||||
if (wrs == NULL && nwrs > 0)
|
||||
if ((wrs != NULL && (nwrs == 0 || nwrs > INT32_MAX)) || (wrs == NULL && nwrs != 0))
|
||||
return DDS_RETCODE_BAD_PARAMETER;
|
||||
if ((rc = dds_reader_lock (reader, &rd)) != DDS_RETCODE_OK)
|
||||
return rc;
|
||||
else
|
||||
{
|
||||
const struct ephash *gh = rd->m_entity.m_domain->gv.guid_hash;
|
||||
const int32_t nwrs_max = (nwrs > INT32_MAX) ? INT32_MAX : (int32_t) nwrs;
|
||||
int32_t nwrs_act = 0;
|
||||
size_t nwrs_act = 0;
|
||||
ddsrt_avl_iter_t it;
|
||||
/* FIXME: this ought not be so tightly coupled to the lower layer */
|
||||
thread_state_awake (lookup_thread_state (), &rd->m_entity.m_domain->gv);
|
||||
|
@ -95,7 +96,7 @@ dds_return_t dds_get_matched_publications (dds_entity_t reader, dds_instance_han
|
|||
struct proxy_writer *pwr;
|
||||
if ((pwr = ephash_lookup_proxy_writer_guid (gh, &m->pwr_guid)) != NULL)
|
||||
{
|
||||
if (nwrs_act < nwrs_max)
|
||||
if (nwrs_act < nwrs)
|
||||
wrs[nwrs_act] = pwr->e.iid;
|
||||
nwrs_act++;
|
||||
}
|
||||
|
@ -107,7 +108,7 @@ dds_return_t dds_get_matched_publications (dds_entity_t reader, dds_instance_han
|
|||
struct writer *wr;
|
||||
if ((wr = ephash_lookup_writer_guid (gh, &m->wr_guid)) != NULL)
|
||||
{
|
||||
if (nwrs_act < nwrs_max)
|
||||
if (nwrs_act < nwrs)
|
||||
wrs[nwrs_act] = wr->e.iid;
|
||||
nwrs_act++;
|
||||
}
|
||||
|
@ -115,14 +116,17 @@ dds_return_t dds_get_matched_publications (dds_entity_t reader, dds_instance_han
|
|||
ddsrt_mutex_unlock (&rd->m_rd->e.lock);
|
||||
thread_state_asleep (lookup_thread_state ());
|
||||
dds_reader_unlock (rd);
|
||||
return nwrs_act;
|
||||
/* FIXME: is it really true that there can not be more than INT32_MAX matching readers?
|
||||
(in practice it'll come to a halt long before that) */
|
||||
assert (nwrs_act <= INT32_MAX);
|
||||
return (dds_return_t) nwrs_act;
|
||||
}
|
||||
}
|
||||
|
||||
static dds_builtintopic_endpoint_t *make_builtintopic_endpoint (const nn_guid_t *guid, const nn_guid_t *ppguid, dds_instance_handle_t ppiid, const dds_qos_t *qos)
|
||||
static dds_builtintopic_endpoint_t *make_builtintopic_endpoint (const ddsi_guid_t *guid, const ddsi_guid_t *ppguid, dds_instance_handle_t ppiid, const dds_qos_t *qos)
|
||||
{
|
||||
dds_builtintopic_endpoint_t *ep;
|
||||
nn_guid_t tmp;
|
||||
ddsi_guid_t tmp;
|
||||
ep = dds_alloc (sizeof (*ep));
|
||||
tmp = nn_hton_guid (*guid);
|
||||
memcpy (&ep->key, &tmp, sizeof (ep->key));
|
||||
|
|
|
@ -12,11 +12,13 @@
|
|||
#include <assert.h>
|
||||
|
||||
#include "dds/ddsrt/cdtors.h"
|
||||
#include "dds/ddsrt/environ.h"
|
||||
#include "dds/ddsi/q_entity.h"
|
||||
#include "dds/ddsi/q_thread.h"
|
||||
#include "dds/ddsi/q_config.h"
|
||||
#include "dds/ddsi/q_plist.h"
|
||||
#include "dds/ddsi/q_globals.h"
|
||||
#include "dds/version.h"
|
||||
#include "dds__init.h"
|
||||
#include "dds__domain.h"
|
||||
#include "dds__participant.h"
|
||||
|
@ -42,14 +44,7 @@ static dds_return_t dds_participant_delete (dds_entity *e)
|
|||
thread_state_awake (lookup_thread_state (), &e->m_domain->gv);
|
||||
if ((ret = delete_participant (&e->m_domain->gv, &e->m_guid)) < 0)
|
||||
DDS_CERROR (&e->m_domain->gv.logconfig, "dds_participant_delete: internal error %"PRId32"\n", ret);
|
||||
ddsrt_mutex_lock (&dds_global.m_mutex);
|
||||
ddsrt_avl_delete (&dds_entity_children_td, &e->m_domain->m_ppants, e);
|
||||
ddsrt_mutex_unlock (&dds_global.m_mutex);
|
||||
thread_state_asleep (lookup_thread_state ());
|
||||
|
||||
/* Every dds_init needs a dds_fini. */
|
||||
dds_domain_free (e->m_domain);
|
||||
dds_fini ();
|
||||
return DDS_RETCODE_OK;
|
||||
}
|
||||
|
||||
|
@ -74,6 +69,7 @@ static dds_return_t dds_participant_qos_set (dds_entity *e, const dds_qos_t *qos
|
|||
}
|
||||
|
||||
const struct dds_entity_deriver dds_entity_deriver_participant = {
|
||||
.interrupt = dds_entity_deriver_dummy_interrupt,
|
||||
.close = dds_entity_deriver_dummy_close,
|
||||
.delete = dds_participant_delete,
|
||||
.set_qos = dds_participant_qos_set,
|
||||
|
@ -84,16 +80,19 @@ dds_entity_t dds_create_participant (const dds_domainid_t domain, const dds_qos_
|
|||
{
|
||||
dds_domain *dom;
|
||||
dds_entity_t ret;
|
||||
nn_guid_t guid;
|
||||
ddsi_guid_t guid;
|
||||
dds_participant * pp;
|
||||
nn_plist_t plist;
|
||||
dds_qos_t *new_qos = NULL;
|
||||
char *config = "";
|
||||
|
||||
/* Make sure DDS instance is initialized. */
|
||||
if ((ret = dds_init ()) < 0)
|
||||
goto err_dds_init;
|
||||
|
||||
if ((ret = dds_domain_create (&dom, domain)) < 0)
|
||||
(void) ddsrt_getenv (DDS_PROJECT_NAME_NOSPACE_CAPS"_URI", &config);
|
||||
|
||||
if ((ret = dds_domain_create_internal (&dom, domain, true, config)) < 0)
|
||||
goto err_domain_create;
|
||||
|
||||
new_qos = dds_create_qos ();
|
||||
|
@ -118,7 +117,7 @@ dds_entity_t dds_create_participant (const dds_domainid_t domain, const dds_qos_
|
|||
}
|
||||
|
||||
pp = dds_alloc (sizeof (*pp));
|
||||
if ((ret = dds_entity_init (&pp->m_entity, NULL, DDS_KIND_PARTICIPANT, new_qos, listener, DDS_PARTICIPANT_STATUS_MASK)) < 0)
|
||||
if ((ret = dds_entity_init (&pp->m_entity, &dom->m_entity, DDS_KIND_PARTICIPANT, new_qos, listener, DDS_PARTICIPANT_STATUS_MASK)) < 0)
|
||||
goto err_entity_init;
|
||||
|
||||
pp->m_entity.m_guid = guid;
|
||||
|
@ -127,9 +126,14 @@ dds_entity_t dds_create_participant (const dds_domainid_t domain, const dds_qos_
|
|||
pp->m_builtin_subscriber = 0;
|
||||
|
||||
/* Add participant to extent */
|
||||
ddsrt_mutex_lock (&dds_global.m_mutex);
|
||||
ddsrt_avl_insert (&dds_entity_children_td, &dom->m_ppants, &pp->m_entity);
|
||||
ddsrt_mutex_unlock (&dds_global.m_mutex);
|
||||
ddsrt_mutex_lock (&dds_global.m_entity.m_mutex);
|
||||
dds_entity_register_child (&dom->m_entity, &pp->m_entity);
|
||||
ddsrt_mutex_unlock (&dds_global.m_entity.m_mutex);
|
||||
|
||||
dds_entity_init_complete (&pp->m_entity);
|
||||
/* drop temporary extra ref to domain, dds_init */
|
||||
dds_delete (dom->m_entity.m_hdllink.hdl);
|
||||
dds_delete_impl_pinned (&dds_global.m_entity, DIS_EXPLICIT);
|
||||
return ret;
|
||||
|
||||
err_entity_init:
|
||||
|
@ -137,43 +141,40 @@ err_entity_init:
|
|||
err_new_participant:
|
||||
err_qos_validation:
|
||||
dds_delete_qos (new_qos);
|
||||
dds_domain_free (dom);
|
||||
dds_delete (dom->m_entity.m_hdllink.hdl);
|
||||
err_domain_create:
|
||||
dds_fini ();
|
||||
dds_delete_impl_pinned (&dds_global.m_entity, DIS_EXPLICIT);
|
||||
err_dds_init:
|
||||
return ret;
|
||||
}
|
||||
|
||||
dds_entity_t dds_lookup_participant (dds_domainid_t domain_id, dds_entity_t *participants, size_t size)
|
||||
dds_return_t dds_lookup_participant (dds_domainid_t domain_id, dds_entity_t *participants, size_t size)
|
||||
{
|
||||
if ((participants != NULL && (size <= 0 || size >= INT32_MAX)) || (participants == NULL && size != 0))
|
||||
return DDS_RETCODE_BAD_PARAMETER;
|
||||
dds_return_t ret;
|
||||
|
||||
ddsrt_init ();
|
||||
ddsrt_mutex_t * const init_mutex = ddsrt_get_singleton_mutex ();
|
||||
if ((participants != NULL && (size == 0 || size >= INT32_MAX)) || (participants == NULL && size != 0))
|
||||
return DDS_RETCODE_BAD_PARAMETER;
|
||||
|
||||
if (participants)
|
||||
participants[0] = 0;
|
||||
|
||||
dds_return_t ret = 0;
|
||||
ddsrt_mutex_lock (init_mutex);
|
||||
if (dds_global.m_init_count > 0)
|
||||
if ((ret = dds_init ()) < 0)
|
||||
return ret;
|
||||
|
||||
ret = 0;
|
||||
struct dds_domain *dom;
|
||||
ddsrt_mutex_lock (&dds_global.m_mutex);
|
||||
if ((dom = dds_domain_find_locked (domain_id)) != NULL)
|
||||
{
|
||||
struct dds_domain *dom;
|
||||
ddsrt_mutex_lock (&dds_global.m_mutex);
|
||||
if ((dom = dds_domain_find_locked (domain_id)) != NULL)
|
||||
ddsrt_avl_iter_t it;
|
||||
for (dds_entity *e = ddsrt_avl_iter_first (&dds_entity_children_td, &dom->m_entity.m_children, &it); e != NULL; e = ddsrt_avl_iter_next (&it))
|
||||
{
|
||||
ddsrt_avl_iter_t it;
|
||||
for (dds_entity *e = ddsrt_avl_iter_first (&dds_entity_children_td, &dom->m_ppants, &it); e != NULL; e = ddsrt_avl_iter_next (&it))
|
||||
{
|
||||
if ((size_t) ret < size)
|
||||
participants[ret] = e->m_hdllink.hdl;
|
||||
ret++;
|
||||
}
|
||||
if ((size_t) ret < size)
|
||||
participants[ret] = e->m_hdllink.hdl;
|
||||
ret++;
|
||||
}
|
||||
ddsrt_mutex_unlock (&dds_global.m_mutex);
|
||||
}
|
||||
ddsrt_mutex_unlock (init_mutex);
|
||||
ddsrt_fini ();
|
||||
ddsrt_mutex_unlock (&dds_global.m_mutex);
|
||||
dds_delete_impl_pinned (&dds_global.m_entity, DIS_EXPLICIT);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@ static dds_return_t dds_publisher_status_validate (uint32_t mask)
|
|||
}
|
||||
|
||||
const struct dds_entity_deriver dds_entity_deriver_publisher = {
|
||||
.interrupt = dds_entity_deriver_dummy_interrupt,
|
||||
.close = dds_entity_deriver_dummy_close,
|
||||
.delete = dds_entity_deriver_dummy_delete,
|
||||
.set_qos = dds_publisher_qos_set,
|
||||
|
@ -69,6 +70,7 @@ dds_entity_t dds_create_publisher (dds_entity_t participant, const dds_qos_t *qo
|
|||
hdl = dds_entity_init (&pub->m_entity, &par->m_entity, DDS_KIND_PUBLISHER, new_qos, listener, DDS_PUBLISHER_STATUS_MASK);
|
||||
pub->m_entity.m_iid = ddsi_iid_gen ();
|
||||
dds_entity_register_child (&par->m_entity, &pub->m_entity);
|
||||
dds_entity_init_complete (&pub->m_entity);
|
||||
dds_participant_unlock (par);
|
||||
return hdl;
|
||||
}
|
||||
|
|
|
@ -33,8 +33,9 @@ dds_entity_t dds_create_querycondition (dds_entity_t reader, uint32_t mask, dds_
|
|||
dds_entity_t hdl;
|
||||
dds_readcond *cond = dds_create_readcond (r, DDS_KIND_COND_QUERY, mask, filter);
|
||||
assert (cond);
|
||||
dds_reader_unlock (r);
|
||||
hdl = cond->m_entity.m_hdllink.hdl;
|
||||
dds_entity_init_complete (&cond->m_entity);
|
||||
dds_reader_unlock (r);
|
||||
return hdl;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#include "dds__entity.h"
|
||||
#include "dds__reader.h"
|
||||
#include "dds/ddsi/ddsi_tkmap.h"
|
||||
#include "dds__rhc.h"
|
||||
#include "dds/ddsc/dds_rhc.h"
|
||||
#include "dds/ddsi/q_thread.h"
|
||||
#include "dds/ddsi/q_ephash.h"
|
||||
#include "dds/ddsi/q_entity.h"
|
||||
|
@ -130,7 +130,7 @@ static dds_return_t dds_read_impl (bool take, dds_entity_t reader_or_condition,
|
|||
if (nodata_cleanups & NC_CLEAR_LOAN_OUT)
|
||||
rd->m_loan_out = false;
|
||||
if (nodata_cleanups & NC_FREE_BUF)
|
||||
ddsi_sertopic_free_samples (rd->m_topic->m_stopic, buf[0], maxs, DDS_FREE_ALL);
|
||||
ddsi_sertopic_free_samples (rd->m_topic->m_stopic, buf, maxs, DDS_FREE_ALL);
|
||||
if (nodata_cleanups & NC_RESET_BUF)
|
||||
buf[0] = NULL;
|
||||
ddsrt_mutex_unlock (&rd->m_entity.m_mutex);
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#include <assert.h>
|
||||
#include "dds__reader.h"
|
||||
#include "dds__readcond.h"
|
||||
#include "dds__rhc.h"
|
||||
#include "dds/ddsc/dds_rhc.h"
|
||||
#include "dds__entity.h"
|
||||
#include "dds/ddsi/ddsi_iid.h"
|
||||
#include "dds/ddsi/q_ephash.h"
|
||||
|
@ -23,11 +23,14 @@ static dds_return_t dds_readcond_delete (dds_entity *e) ddsrt_nonnull_all;
|
|||
|
||||
static dds_return_t dds_readcond_delete (dds_entity *e)
|
||||
{
|
||||
dds_rhc_remove_readcondition ((dds_readcond *) e);
|
||||
struct dds_reader * const rd = (struct dds_reader *) e->m_parent;
|
||||
assert (dds_entity_kind (&rd->m_entity) == DDS_KIND_READER);
|
||||
dds_rhc_remove_readcondition (rd->m_rhc, (dds_readcond *) e);
|
||||
return DDS_RETCODE_OK;
|
||||
}
|
||||
|
||||
const struct dds_entity_deriver dds_entity_deriver_readcondition = {
|
||||
.interrupt = dds_entity_deriver_dummy_interrupt,
|
||||
.close = dds_entity_deriver_dummy_close,
|
||||
.delete = dds_readcond_delete,
|
||||
.set_qos = dds_entity_deriver_dummy_set_qos,
|
||||
|
@ -41,17 +44,15 @@ dds_readcond *dds_create_readcond (dds_reader *rd, dds_entity_kind_t kind, uint3
|
|||
(void) dds_entity_init (&cond->m_entity, &rd->m_entity, kind, NULL, NULL, 0);
|
||||
cond->m_entity.m_iid = ddsi_iid_gen ();
|
||||
dds_entity_register_child (&rd->m_entity, &cond->m_entity);
|
||||
cond->m_rhc = rd->m_rhc;
|
||||
cond->m_sample_states = mask & DDS_ANY_SAMPLE_STATE;
|
||||
cond->m_view_states = mask & DDS_ANY_VIEW_STATE;
|
||||
cond->m_instance_states = mask & DDS_ANY_INSTANCE_STATE;
|
||||
cond->m_rd_guid = rd->m_entity.m_guid;
|
||||
if (kind == DDS_KIND_COND_QUERY)
|
||||
{
|
||||
cond->m_query.m_filter = filter;
|
||||
cond->m_query.m_qcmask = 0;
|
||||
}
|
||||
if (!dds_rhc_add_readcondition (cond))
|
||||
if (!dds_rhc_add_readcondition (rd->m_rhc, cond))
|
||||
{
|
||||
/* FIXME: current entity management code can't deal with an error late in the creation of the
|
||||
entity because it doesn't allow deleting it again ... */
|
||||
|
@ -72,6 +73,7 @@ dds_entity_t dds_create_readcondition (dds_entity_t reader, uint32_t mask)
|
|||
dds_readcond *cond = dds_create_readcond(rd, DDS_KIND_COND_READ, mask, 0);
|
||||
assert (cond);
|
||||
hdl = cond->m_entity.m_hdllink.hdl;
|
||||
dds_entity_init_complete (&cond->m_entity);
|
||||
dds_reader_unlock (rd);
|
||||
return hdl;
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
#include "dds__reader.h"
|
||||
#include "dds__listener.h"
|
||||
#include "dds__init.h"
|
||||
#include "dds__rhc.h"
|
||||
#include "dds/ddsc/dds_rhc.h"
|
||||
#include "dds__rhc_default.h"
|
||||
#include "dds__topic.h"
|
||||
#include "dds__get_status.h"
|
||||
|
@ -40,16 +40,21 @@ DECL_ENTITY_LOCK_UNLOCK (extern inline, dds_reader)
|
|||
DDS_SAMPLE_LOST_STATUS |\
|
||||
DDS_SUBSCRIPTION_MATCHED_STATUS)
|
||||
|
||||
static dds_return_t dds_reader_close (dds_entity *e) ddsrt_nonnull_all;
|
||||
static void dds_reader_close (dds_entity *e) ddsrt_nonnull_all;
|
||||
|
||||
static dds_return_t dds_reader_close (dds_entity *e)
|
||||
static void dds_reader_close (dds_entity *e)
|
||||
{
|
||||
dds_return_t ret = DDS_RETCODE_OK;
|
||||
struct dds_reader * const rd = (struct dds_reader *) e;
|
||||
assert (rd->m_rd != NULL);
|
||||
|
||||
thread_state_awake (lookup_thread_state (), &e->m_domain->gv);
|
||||
if (delete_reader (&e->m_domain->gv, &e->m_guid) != 0)
|
||||
ret = DDS_RETCODE_ERROR;
|
||||
(void) delete_reader (&e->m_domain->gv, &e->m_guid);
|
||||
thread_state_asleep (lookup_thread_state ());
|
||||
return ret;
|
||||
|
||||
ddsrt_mutex_lock (&e->m_mutex);
|
||||
while (rd->m_rd != NULL)
|
||||
ddsrt_cond_wait (&e->m_cond, &e->m_mutex);
|
||||
ddsrt_mutex_unlock (&e->m_mutex);
|
||||
}
|
||||
|
||||
static dds_return_t dds_reader_delete (dds_entity *e) ddsrt_nonnull_all;
|
||||
|
@ -57,17 +62,12 @@ static dds_return_t dds_reader_delete (dds_entity *e) ddsrt_nonnull_all;
|
|||
static dds_return_t dds_reader_delete (dds_entity *e)
|
||||
{
|
||||
dds_reader * const rd = (dds_reader *) e;
|
||||
dds_return_t ret;
|
||||
if ((ret = dds_delete (rd->m_topic->m_entity.m_hdllink.hdl)) == DDS_RETCODE_OK)
|
||||
{
|
||||
/* Delete an implicitly created parent; for normal ones, this is expected
|
||||
to fail with BAD_PARAMETER - FIXME: there must be a cleaner way */
|
||||
ret = dds_delete_impl (e->m_parent->m_hdllink.hdl, true);
|
||||
if (ret == DDS_RETCODE_BAD_PARAMETER)
|
||||
ret = DDS_RETCODE_OK;
|
||||
}
|
||||
(void) dds_delete (rd->m_topic->m_entity.m_hdllink.hdl);
|
||||
dds_free (rd->m_loan);
|
||||
return ret;
|
||||
thread_state_awake (lookup_thread_state (), &e->m_domain->gv);
|
||||
dds_rhc_free (rd->m_rhc);
|
||||
thread_state_asleep (lookup_thread_state ());
|
||||
return DDS_RETCODE_OK;
|
||||
}
|
||||
|
||||
static dds_return_t dds_reader_qos_set (dds_entity *e, const dds_qos_t *qos, bool enabled)
|
||||
|
@ -97,11 +97,14 @@ void dds_reader_data_available_cb (struct dds_reader *rd)
|
|||
overhead really matters. Otherwise, it is pretty much like
|
||||
dds_reader_status_cb. */
|
||||
|
||||
const bool data_av_enabled = (ddsrt_atomic_ld32 (&rd->m_entity.m_status.m_status_and_mask) & (DDS_DATA_AVAILABLE_STATUS << SAM_ENABLED_SHIFT));
|
||||
if (!data_av_enabled)
|
||||
const uint32_t data_av_enabled = (ddsrt_atomic_ld32 (&rd->m_entity.m_status.m_status_and_mask) & (DDS_DATA_AVAILABLE_STATUS << SAM_ENABLED_SHIFT));
|
||||
if (data_av_enabled == 0)
|
||||
return;
|
||||
|
||||
ddsrt_mutex_lock (&rd->m_entity.m_observers_lock);
|
||||
rd->m_entity.m_cb_pending_count++;
|
||||
|
||||
/* FIXME: why wait if no listener is set? */
|
||||
while (rd->m_entity.m_cb_count > 0)
|
||||
ddsrt_cond_wait (&rd->m_entity.m_observers_cond, &rd->m_entity.m_observers_lock);
|
||||
rd->m_entity.m_cb_count++;
|
||||
|
@ -111,20 +114,25 @@ void dds_reader_data_available_cb (struct dds_reader *rd)
|
|||
if (lst->on_data_on_readers)
|
||||
{
|
||||
ddsrt_mutex_unlock (&rd->m_entity.m_observers_lock);
|
||||
|
||||
ddsrt_mutex_lock (&sub->m_observers_lock);
|
||||
while (sub->m_cb_count > 0)
|
||||
ddsrt_cond_wait (&sub->m_observers_cond, &sub->m_observers_lock);
|
||||
sub->m_cb_count++;
|
||||
const uint32_t data_on_rds_enabled = (ddsrt_atomic_ld32 (&sub->m_status.m_status_and_mask) & (DDS_DATA_ON_READERS_STATUS << SAM_ENABLED_SHIFT));
|
||||
if (data_on_rds_enabled)
|
||||
{
|
||||
sub->m_cb_pending_count++;
|
||||
while (sub->m_cb_count > 0)
|
||||
ddsrt_cond_wait (&sub->m_observers_cond, &sub->m_observers_lock);
|
||||
sub->m_cb_count++;
|
||||
ddsrt_mutex_unlock (&sub->m_observers_lock);
|
||||
|
||||
lst->on_data_on_readers (sub->m_hdllink.hdl, lst->on_data_on_readers_arg);
|
||||
|
||||
ddsrt_mutex_lock (&sub->m_observers_lock);
|
||||
sub->m_cb_count--;
|
||||
sub->m_cb_pending_count--;
|
||||
ddsrt_cond_broadcast (&sub->m_observers_cond);
|
||||
}
|
||||
ddsrt_mutex_unlock (&sub->m_observers_lock);
|
||||
|
||||
lst->on_data_on_readers (sub->m_hdllink.hdl, lst->on_data_on_readers_arg);
|
||||
|
||||
ddsrt_mutex_lock (&rd->m_entity.m_observers_lock);
|
||||
ddsrt_mutex_lock (&sub->m_observers_lock);
|
||||
sub->m_cb_count--;
|
||||
ddsrt_cond_broadcast (&sub->m_observers_cond);
|
||||
ddsrt_mutex_unlock (&sub->m_observers_lock);
|
||||
}
|
||||
else if (rd->m_entity.m_listener.on_data_available)
|
||||
{
|
||||
|
@ -141,24 +149,28 @@ void dds_reader_data_available_cb (struct dds_reader *rd)
|
|||
}
|
||||
|
||||
rd->m_entity.m_cb_count--;
|
||||
rd->m_entity.m_cb_pending_count--;
|
||||
ddsrt_cond_broadcast (&rd->m_entity.m_observers_cond);
|
||||
ddsrt_mutex_unlock (&rd->m_entity.m_observers_lock);
|
||||
}
|
||||
|
||||
void dds_reader_status_cb (void *ventity, const status_cb_data_t *data)
|
||||
{
|
||||
struct dds_entity * const entity = ventity;
|
||||
dds_reader * const rd = ventity;
|
||||
|
||||
/* When data is NULL, it means that the DDSI reader is deleted. */
|
||||
if (data == NULL)
|
||||
{
|
||||
/* Release the initial claim that was done during the create. This
|
||||
* will indicate that further API deletion is now possible. */
|
||||
dds_handle_unpin (&entity->m_hdllink);
|
||||
ddsrt_mutex_lock (&rd->m_entity.m_mutex);
|
||||
rd->m_rd = NULL;
|
||||
ddsrt_cond_broadcast (&rd->m_entity.m_cond);
|
||||
ddsrt_mutex_unlock (&rd->m_entity.m_mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
struct dds_listener const * const lst = &entity->m_listener;
|
||||
struct dds_listener const * const lst = &rd->m_entity.m_listener;
|
||||
enum dds_status_id status_id = (enum dds_status_id) data->raw_status_id;
|
||||
bool invoke = false;
|
||||
void *vst = NULL;
|
||||
|
@ -175,13 +187,12 @@ void dds_reader_status_cb (void *ventity, const status_cb_data_t *data)
|
|||
m_observers_lock for the duration of the listener call itself,
|
||||
and that similarly the listener function and argument pointers
|
||||
are stable */
|
||||
ddsrt_mutex_lock (&entity->m_observers_lock);
|
||||
while (entity->m_cb_count > 0)
|
||||
ddsrt_cond_wait (&entity->m_observers_cond, &entity->m_observers_lock);
|
||||
entity->m_cb_count++;
|
||||
/* FIXME: why do this if no listener is set? */
|
||||
ddsrt_mutex_lock (&rd->m_entity.m_observers_lock);
|
||||
while (rd->m_entity.m_cb_count > 0)
|
||||
ddsrt_cond_wait (&rd->m_entity.m_observers_cond, &rd->m_entity.m_observers_lock);
|
||||
|
||||
/* Update status metrics. */
|
||||
dds_reader * const rd = (dds_reader *) entity;
|
||||
switch (status_id) {
|
||||
case DDS_REQUESTED_DEADLINE_MISSED_STATUS_ID: {
|
||||
struct dds_requested_deadline_missed_status * const st = vst = &rd->m_requested_deadline_missed_status;
|
||||
|
@ -265,36 +276,46 @@ void dds_reader_status_cb (void *ventity, const status_cb_data_t *data)
|
|||
assert (0);
|
||||
}
|
||||
|
||||
if (invoke)
|
||||
const uint32_t enabled = (ddsrt_atomic_ld32 (&rd->m_entity.m_status.m_status_and_mask) & ((1u << status_id) << SAM_ENABLED_SHIFT));
|
||||
if (!enabled)
|
||||
{
|
||||
ddsrt_mutex_unlock (&entity->m_observers_lock);
|
||||
dds_entity_invoke_listener (entity, status_id, vst);
|
||||
ddsrt_mutex_lock (&entity->m_observers_lock);
|
||||
/* Don't invoke listeners or set status flag if masked */
|
||||
}
|
||||
else if (invoke)
|
||||
{
|
||||
rd->m_entity.m_cb_pending_count++;
|
||||
rd->m_entity.m_cb_count++;
|
||||
ddsrt_mutex_unlock (&rd->m_entity.m_observers_lock);
|
||||
dds_entity_invoke_listener (&rd->m_entity, status_id, vst);
|
||||
ddsrt_mutex_lock (&rd->m_entity.m_observers_lock);
|
||||
rd->m_entity.m_cb_count--;
|
||||
rd->m_entity.m_cb_pending_count--;
|
||||
*reset[0] = 0;
|
||||
if (reset[1])
|
||||
*reset[1] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
dds_entity_status_set (entity, (status_mask_t) (1u << status_id));
|
||||
dds_entity_status_set (&rd->m_entity, (status_mask_t) (1u << status_id));
|
||||
}
|
||||
|
||||
entity->m_cb_count--;
|
||||
ddsrt_cond_broadcast (&entity->m_observers_cond);
|
||||
ddsrt_mutex_unlock (&entity->m_observers_lock);
|
||||
ddsrt_cond_broadcast (&rd->m_entity.m_observers_cond);
|
||||
ddsrt_mutex_unlock (&rd->m_entity.m_observers_lock);
|
||||
}
|
||||
|
||||
const struct dds_entity_deriver dds_entity_deriver_reader = {
|
||||
.interrupt = dds_entity_deriver_dummy_interrupt,
|
||||
.close = dds_reader_close,
|
||||
.delete = dds_reader_delete,
|
||||
.set_qos = dds_reader_qos_set,
|
||||
.validate_status = dds_reader_status_validate
|
||||
};
|
||||
|
||||
dds_entity_t dds_create_reader (dds_entity_t participant_or_subscriber, dds_entity_t topic, const dds_qos_t *qos, const dds_listener_t *listener)
|
||||
static dds_entity_t dds_create_reader_int (dds_entity_t participant_or_subscriber, dds_entity_t topic, const dds_qos_t *qos, const dds_listener_t *listener, struct dds_rhc *rhc)
|
||||
{
|
||||
dds_qos_t *rqos;
|
||||
dds_subscriber *sub = NULL;
|
||||
dds_participant *pp;
|
||||
dds_entity_t subscriber;
|
||||
dds_reader *rd;
|
||||
dds_topic *tp;
|
||||
|
@ -347,8 +368,12 @@ dds_entity_t dds_create_reader (dds_entity_t participant_or_subscriber, dds_enti
|
|||
goto err_tp_lock;
|
||||
}
|
||||
assert (tp->m_stopic);
|
||||
/* FIXME: domain check */
|
||||
assert (sub->m_entity.m_domain == tp->m_entity.m_domain);
|
||||
pp = dds_entity_participant (&sub->m_entity);
|
||||
if (pp != dds_entity_participant (&tp->m_entity))
|
||||
{
|
||||
reader = DDS_RETCODE_BAD_PARAMETER;
|
||||
goto err_pp_mismatch;
|
||||
}
|
||||
|
||||
/* Merge qos from topic and subscriber, dds_copy_qos only fails when it is passed a null
|
||||
argument, but that isn't the case here */
|
||||
|
@ -378,28 +403,29 @@ dds_entity_t dds_create_reader (dds_entity_t participant_or_subscriber, dds_enti
|
|||
goto err_bad_qos;
|
||||
}
|
||||
|
||||
/* Create reader and associated read cache */
|
||||
/* Create reader and associated read cache (if not provided by caller) */
|
||||
rd = dds_alloc (sizeof (*rd));
|
||||
reader = dds_entity_init (&rd->m_entity, &sub->m_entity, DDS_KIND_READER, rqos, listener, DDS_READER_STATUS_MASK);
|
||||
rd->m_sample_rejected_status.last_reason = DDS_NOT_REJECTED;
|
||||
rd->m_topic = tp;
|
||||
rd->m_rhc = dds_rhc_default_new (rd, tp->m_stopic);
|
||||
rd->m_rhc = rhc ? rhc : dds_rhc_default_new (rd, tp->m_stopic);
|
||||
if (dds_rhc_associate (rd->m_rhc, rd, tp->m_stopic, rd->m_entity.m_domain->gv.m_tkmap) < 0)
|
||||
{
|
||||
/* FIXME: see also create_querycond, need to be able to undo entity_init */
|
||||
abort ();
|
||||
}
|
||||
dds_entity_add_ref_locked (&tp->m_entity);
|
||||
|
||||
/* Extra claim of this reader to make sure that the delete waits until DDSI
|
||||
has deleted its reader as well. This can be known through the callback. */
|
||||
dds_handle_repin (&rd->m_entity.m_hdllink);
|
||||
|
||||
ddsrt_mutex_unlock (&tp->m_entity.m_mutex);
|
||||
ddsrt_mutex_unlock (&sub->m_entity.m_mutex);
|
||||
/* FIXME: listeners can come too soon ... should set mask based on listeners
|
||||
then atomically set the listeners, save the mask to a pending set and clear
|
||||
it; and then invoke those listeners that are in the pending set */
|
||||
dds_entity_init_complete (&rd->m_entity);
|
||||
|
||||
thread_state_awake (lookup_thread_state (), &sub->m_entity.m_domain->gv);
|
||||
ret = new_reader (&rd->m_rd, &rd->m_entity.m_domain->gv, &rd->m_entity.m_guid, NULL, &sub->m_entity.m_participant->m_guid, tp->m_stopic, rqos, &rd->m_rhc->common.rhc, dds_reader_status_cb, rd);
|
||||
ddsrt_mutex_lock (&sub->m_entity.m_mutex);
|
||||
ddsrt_mutex_lock (&tp->m_entity.m_mutex);
|
||||
ret = new_reader (&rd->m_rd, &rd->m_entity.m_domain->gv, &rd->m_entity.m_guid, NULL, &pp->m_entity.m_guid, tp->m_stopic, rqos, &rd->m_rhc->common.rhc, dds_reader_status_cb, rd);
|
||||
assert (ret == DDS_RETCODE_OK); /* FIXME: can be out-of-resources at the very least */
|
||||
thread_state_asleep (lookup_thread_state ());
|
||||
|
||||
|
||||
rd->m_entity.m_iid = get_entity_instance_id (&rd->m_entity.m_domain->gv, &rd->m_entity.m_guid);
|
||||
dds_entity_register_child (&sub->m_entity, &rd->m_entity);
|
||||
|
||||
|
@ -414,6 +440,7 @@ dds_entity_t dds_create_reader (dds_entity_t participant_or_subscriber, dds_enti
|
|||
return reader;
|
||||
|
||||
err_bad_qos:
|
||||
err_pp_mismatch:
|
||||
dds_topic_unlock (tp);
|
||||
err_tp_lock:
|
||||
dds_subscriber_unlock (sub);
|
||||
|
@ -438,7 +465,7 @@ void dds_reader_ddsi2direct (dds_entity_t entity, ddsi2direct_directread_cb_t cb
|
|||
|
||||
dds_reader *dds_rd = (dds_reader *) dds_entity;
|
||||
struct reader *rd = dds_rd->m_rd;
|
||||
nn_guid_t pwrguid;
|
||||
ddsi_guid_t pwrguid;
|
||||
struct proxy_writer *pwr;
|
||||
struct rd_pwr_match *m;
|
||||
memset (&pwrguid, 0, sizeof (pwrguid));
|
||||
|
@ -451,7 +478,7 @@ void dds_reader_ddsi2direct (dds_entity_t entity, ddsi2direct_directread_cb_t cb
|
|||
/* have to be careful walking the tree -- pretty is different, but
|
||||
I want to check this before I write a lookup_succ function. */
|
||||
struct rd_pwr_match *m_next;
|
||||
nn_guid_t pwrguid_next;
|
||||
ddsi_guid_t pwrguid_next;
|
||||
pwrguid = m->pwr_guid;
|
||||
if ((m_next = ddsrt_avl_find_succ (&rd_writers_treedef, &rd->writers, m)) != NULL)
|
||||
pwrguid_next = m_next->pwr_guid;
|
||||
|
@ -475,6 +502,18 @@ void dds_reader_ddsi2direct (dds_entity_t entity, ddsi2direct_directread_cb_t cb
|
|||
dds_entity_unpin (dds_entity);
|
||||
}
|
||||
|
||||
dds_entity_t dds_create_reader (dds_entity_t participant_or_subscriber, dds_entity_t topic, const dds_qos_t *qos, const dds_listener_t *listener)
|
||||
{
|
||||
return dds_create_reader_int (participant_or_subscriber, topic, qos, listener, NULL);
|
||||
}
|
||||
|
||||
dds_entity_t dds_create_reader_rhc (dds_entity_t participant_or_subscriber, dds_entity_t topic, const dds_qos_t *qos, const dds_listener_t *listener, struct dds_rhc *rhc)
|
||||
{
|
||||
if (rhc == NULL)
|
||||
return DDS_RETCODE_BAD_PARAMETER;
|
||||
return dds_create_reader_int (participant_or_subscriber, topic, qos, listener, rhc);
|
||||
}
|
||||
|
||||
uint32_t dds_reader_lock_samples (dds_entity_t reader)
|
||||
{
|
||||
dds_reader *rd;
|
||||
|
|
|
@ -11,17 +11,18 @@
|
|||
*/
|
||||
|
||||
#include "dds/dds.h"
|
||||
#include "dds/ddsi/q_rhc.h"
|
||||
#include "dds__rhc.h"
|
||||
#include "dds/ddsi/ddsi_rhc.h"
|
||||
#include "dds/ddsc/dds_rhc.h"
|
||||
|
||||
extern inline bool dds_rhc_store (struct dds_rhc * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info, struct ddsi_serdata * __restrict sample, struct ddsi_tkmap_instance * __restrict tk);
|
||||
extern inline void dds_rhc_unregister_wr (struct dds_rhc * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info);
|
||||
extern inline dds_return_t dds_rhc_associate (struct dds_rhc *rhc, struct dds_reader *reader, const struct ddsi_sertopic *topic, struct ddsi_tkmap *tkmap);
|
||||
extern inline bool dds_rhc_store (struct dds_rhc * __restrict rhc, const struct ddsi_writer_info * __restrict pwr_info, struct ddsi_serdata * __restrict sample, struct ddsi_tkmap_instance * __restrict tk);
|
||||
extern inline void dds_rhc_unregister_wr (struct dds_rhc * __restrict rhc, const struct ddsi_writer_info * __restrict pwr_info);
|
||||
extern inline void dds_rhc_relinquish_ownership (struct dds_rhc * __restrict rhc, const uint64_t wr_iid);
|
||||
extern inline void dds_rhc_set_qos (struct dds_rhc *rhc, const struct dds_qos *qos);
|
||||
extern inline void dds_rhc_free (struct dds_rhc *rhc);
|
||||
extern inline int dds_rhc_read (struct dds_rhc *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, dds_readcond *cond);
|
||||
extern inline int dds_rhc_take (struct dds_rhc *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, dds_readcond *cond);
|
||||
extern inline int dds_rhc_read (struct dds_rhc *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, struct dds_readcond *cond);
|
||||
extern inline int dds_rhc_take (struct dds_rhc *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, struct dds_readcond *cond);
|
||||
extern inline int dds_rhc_takecdr (struct dds_rhc *rhc, bool lock, struct ddsi_serdata **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t sample_states, uint32_t view_states, uint32_t instance_states, dds_instance_handle_t handle);
|
||||
extern inline bool dds_rhc_add_readcondition (struct dds_readcond *cond);
|
||||
extern inline void dds_rhc_remove_readcondition (struct dds_readcond *cond);
|
||||
extern inline bool dds_rhc_add_readcondition (struct dds_rhc *rhc, struct dds_readcond *cond);
|
||||
extern inline void dds_rhc_remove_readcondition (struct dds_rhc *rhc, struct dds_readcond *cond);
|
||||
extern inline uint32_t dds_rhc_lock_samples (struct dds_rhc *rhc);
|
||||
|
|
|
@ -25,12 +25,12 @@
|
|||
|
||||
#include "dds__entity.h"
|
||||
#include "dds__reader.h"
|
||||
#include "dds__rhc.h"
|
||||
#include "dds/ddsc/dds_rhc.h"
|
||||
#include "dds__rhc_default.h"
|
||||
#include "dds/ddsi/ddsi_tkmap.h"
|
||||
#include "dds/ddsrt/hopscotch.h"
|
||||
#include "dds/ddsrt/avl.h"
|
||||
#include "dds/ddsi/q_rhc.h"
|
||||
#include "dds/ddsi/ddsi_rhc.h"
|
||||
#include "dds/ddsi/q_xqos.h"
|
||||
#include "dds/ddsi/q_unused.h"
|
||||
#include "dds/ddsi/q_config.h"
|
||||
|
@ -263,7 +263,7 @@ struct rhc_instance {
|
|||
uint32_t disposed_gen; /* bloody generation counters - worst invention of mankind */
|
||||
uint32_t no_writers_gen; /* __/ */
|
||||
int32_t strength; /* "current" ownership strength */
|
||||
nn_guid_t wr_guid; /* guid of last writer (if wr_iid != 0 then wr_guid is the corresponding guid, else undef) */
|
||||
ddsi_guid_t wr_guid; /* guid of last writer (if wr_iid != 0 then wr_guid is the corresponding guid, else undef) */
|
||||
nn_wctime_t tstamp; /* source time stamp of last update */
|
||||
struct rhc_instance *next; /* next non-empty instance in arbitrary ordering */
|
||||
struct rhc_instance *prev;
|
||||
|
@ -346,30 +346,30 @@ struct trigger_info_post {
|
|||
};
|
||||
|
||||
static void dds_rhc_default_free (struct dds_rhc_default *rhc);
|
||||
static bool dds_rhc_default_store (struct dds_rhc_default * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info, struct ddsi_serdata * __restrict sample, struct ddsi_tkmap_instance * __restrict tk);
|
||||
static void dds_rhc_default_unregister_wr (struct dds_rhc_default * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info);
|
||||
static bool dds_rhc_default_store (struct dds_rhc_default * __restrict rhc, const struct ddsi_writer_info * __restrict wrinfo, struct ddsi_serdata * __restrict sample, struct ddsi_tkmap_instance * __restrict tk);
|
||||
static void dds_rhc_default_unregister_wr (struct dds_rhc_default * __restrict rhc, const struct ddsi_writer_info * __restrict wrinfo);
|
||||
static void dds_rhc_default_relinquish_ownership (struct dds_rhc_default * __restrict rhc, const uint64_t wr_iid);
|
||||
static void dds_rhc_default_set_qos (struct dds_rhc_default *rhc, const struct dds_qos *qos);
|
||||
static int dds_rhc_default_read (struct dds_rhc_default *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, dds_readcond *cond);
|
||||
static int dds_rhc_default_take (struct dds_rhc_default *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, dds_readcond *cond);
|
||||
static int dds_rhc_default_takecdr (struct dds_rhc_default *rhc, bool lock, struct ddsi_serdata ** values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t sample_states, uint32_t view_states, uint32_t instance_states, dds_instance_handle_t handle);
|
||||
static bool dds_rhc_default_add_readcondition (dds_readcond *cond);
|
||||
static void dds_rhc_default_remove_readcondition (dds_readcond *cond);
|
||||
static bool dds_rhc_default_add_readcondition (struct dds_rhc_default *rhc, dds_readcond *cond);
|
||||
static void dds_rhc_default_remove_readcondition (struct dds_rhc_default *rhc, dds_readcond *cond);
|
||||
static uint32_t dds_rhc_default_lock_samples (struct dds_rhc_default *rhc);
|
||||
|
||||
static void dds_rhc_default_free_wrap (struct rhc *rhc) {
|
||||
static void dds_rhc_default_free_wrap (struct ddsi_rhc *rhc) {
|
||||
dds_rhc_default_free ((struct dds_rhc_default *) rhc);
|
||||
}
|
||||
static bool dds_rhc_default_store_wrap (struct rhc * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info, struct ddsi_serdata * __restrict sample, struct ddsi_tkmap_instance * __restrict tk) {
|
||||
return dds_rhc_default_store ((struct dds_rhc_default *) rhc, pwr_info, sample, tk);
|
||||
static bool dds_rhc_default_store_wrap (struct ddsi_rhc * __restrict rhc, const struct ddsi_writer_info * __restrict wrinfo, struct ddsi_serdata * __restrict sample, struct ddsi_tkmap_instance * __restrict tk) {
|
||||
return dds_rhc_default_store ((struct dds_rhc_default *) rhc, wrinfo, sample, tk);
|
||||
}
|
||||
static void dds_rhc_default_unregister_wr_wrap (struct rhc * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info) {
|
||||
dds_rhc_default_unregister_wr ((struct dds_rhc_default *) rhc, pwr_info);
|
||||
static void dds_rhc_default_unregister_wr_wrap (struct ddsi_rhc * __restrict rhc, const struct ddsi_writer_info * __restrict wrinfo) {
|
||||
dds_rhc_default_unregister_wr ((struct dds_rhc_default *) rhc, wrinfo);
|
||||
}
|
||||
static void dds_rhc_default_relinquish_ownership_wrap (struct rhc * __restrict rhc, const uint64_t wr_iid) {
|
||||
static void dds_rhc_default_relinquish_ownership_wrap (struct ddsi_rhc * __restrict rhc, const uint64_t wr_iid) {
|
||||
dds_rhc_default_relinquish_ownership ((struct dds_rhc_default *) rhc, wr_iid);
|
||||
}
|
||||
static void dds_rhc_default_set_qos_wrap (struct rhc *rhc, const struct dds_qos *qos) {
|
||||
static void dds_rhc_default_set_qos_wrap (struct ddsi_rhc *rhc, const struct dds_qos *qos) {
|
||||
dds_rhc_default_set_qos ((struct dds_rhc_default *) rhc, qos);
|
||||
}
|
||||
static int dds_rhc_default_read_wrap (struct dds_rhc *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, dds_readcond *cond) {
|
||||
|
@ -381,15 +381,21 @@ static int dds_rhc_default_take_wrap (struct dds_rhc *rhc, bool lock, void **val
|
|||
static int dds_rhc_default_takecdr_wrap (struct dds_rhc *rhc, bool lock, struct ddsi_serdata **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t sample_states, uint32_t view_states, uint32_t instance_states, dds_instance_handle_t handle) {
|
||||
return dds_rhc_default_takecdr ((struct dds_rhc_default *) rhc, lock, values, info_seq, max_samples, sample_states, view_states, instance_states, handle);
|
||||
}
|
||||
static bool dds_rhc_default_add_readcondition_wrap (dds_readcond *cond) {
|
||||
return dds_rhc_default_add_readcondition (cond);
|
||||
static bool dds_rhc_default_add_readcondition_wrap (struct dds_rhc *rhc, dds_readcond *cond) {
|
||||
return dds_rhc_default_add_readcondition ((struct dds_rhc_default *) rhc, cond);
|
||||
}
|
||||
static void dds_rhc_default_remove_readcondition_wrap (dds_readcond *cond) {
|
||||
dds_rhc_default_remove_readcondition (cond);
|
||||
static void dds_rhc_default_remove_readcondition_wrap (struct dds_rhc *rhc, dds_readcond *cond) {
|
||||
dds_rhc_default_remove_readcondition ((struct dds_rhc_default *) rhc, cond);
|
||||
}
|
||||
static uint32_t dds_rhc_default_lock_samples_wrap (struct dds_rhc *rhc) {
|
||||
return dds_rhc_default_lock_samples ((struct dds_rhc_default *) rhc);
|
||||
}
|
||||
static dds_return_t dds_rhc_default_associate (struct dds_rhc *rhc, dds_reader *reader, const struct ddsi_sertopic *topic, struct ddsi_tkmap *tkmap)
|
||||
{
|
||||
/* ignored out of laziness */
|
||||
(void) rhc; (void) reader; (void) topic; (void) tkmap;
|
||||
return DDS_RETCODE_OK;
|
||||
}
|
||||
|
||||
static const struct dds_rhc_ops dds_rhc_default_ops = {
|
||||
.rhc_ops = {
|
||||
|
@ -404,7 +410,8 @@ static const struct dds_rhc_ops dds_rhc_default_ops = {
|
|||
.takecdr = dds_rhc_default_takecdr_wrap,
|
||||
.add_readcondition = dds_rhc_default_add_readcondition_wrap,
|
||||
.remove_readcondition = dds_rhc_default_remove_readcondition_wrap,
|
||||
.lock_samples = dds_rhc_default_lock_samples_wrap
|
||||
.lock_samples = dds_rhc_default_lock_samples_wrap,
|
||||
.associate = dds_rhc_default_associate
|
||||
};
|
||||
|
||||
static unsigned qmask_of_sample (const struct rhc_sample *s)
|
||||
|
@ -758,7 +765,7 @@ static bool trigger_info_differs (const struct dds_rhc_default *rhc, const struc
|
|||
trig_qc->dec_sample_read != trig_qc->inc_sample_read);
|
||||
}
|
||||
|
||||
static bool add_sample (struct dds_rhc_default *rhc, struct rhc_instance *inst, const struct proxy_writer_info *pwr_info, const struct ddsi_serdata *sample, status_cb_data_t *cb_data, struct trigger_info_qcond *trig_qc)
|
||||
static bool add_sample (struct dds_rhc_default *rhc, struct rhc_instance *inst, const struct ddsi_writer_info *wrinfo, const struct ddsi_serdata *sample, status_cb_data_t *cb_data, struct trigger_info_qcond *trig_qc)
|
||||
{
|
||||
struct rhc_sample *s;
|
||||
|
||||
|
@ -832,7 +839,7 @@ static bool add_sample (struct dds_rhc_default *rhc, struct rhc_instance *inst,
|
|||
}
|
||||
|
||||
s->sample = ddsi_serdata_ref (sample); /* drops const (tho refcount does change) */
|
||||
s->wr_iid = pwr_info->iid;
|
||||
s->wr_iid = wrinfo->iid;
|
||||
s->isread = false;
|
||||
s->disposed_gen = inst->disposed_gen;
|
||||
s->no_writers_gen = inst->no_writers_gen;
|
||||
|
@ -867,12 +874,12 @@ static bool content_filter_accepts (const dds_reader *reader, const struct ddsi_
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int inst_accepts_sample_by_writer_guid (const struct rhc_instance *inst, const struct proxy_writer_info *pwr_info)
|
||||
static int inst_accepts_sample_by_writer_guid (const struct rhc_instance *inst, const struct ddsi_writer_info *wrinfo)
|
||||
{
|
||||
return (inst->wr_iid_islive && inst->wr_iid == pwr_info->iid) || memcmp (&pwr_info->guid, &inst->wr_guid, sizeof (inst->wr_guid)) < 0;
|
||||
return (inst->wr_iid_islive && inst->wr_iid == wrinfo->iid) || memcmp (&wrinfo->guid, &inst->wr_guid, sizeof (inst->wr_guid)) < 0;
|
||||
}
|
||||
|
||||
static int inst_accepts_sample (const struct dds_rhc_default *rhc, const struct rhc_instance *inst, const struct proxy_writer_info *pwr_info, const struct ddsi_serdata *sample, const bool has_data)
|
||||
static int inst_accepts_sample (const struct dds_rhc_default *rhc, const struct rhc_instance *inst, const struct ddsi_writer_info *wrinfo, const struct ddsi_serdata *sample, const bool has_data)
|
||||
{
|
||||
if (rhc->by_source_ordering)
|
||||
{
|
||||
|
@ -884,7 +891,7 @@ static int inst_accepts_sample (const struct dds_rhc_default *rhc, const struct
|
|||
{
|
||||
return 0;
|
||||
}
|
||||
else if (inst_accepts_sample_by_writer_guid (inst, pwr_info))
|
||||
else if (inst_accepts_sample_by_writer_guid (inst, wrinfo))
|
||||
{
|
||||
/* ok */
|
||||
}
|
||||
|
@ -893,14 +900,14 @@ static int inst_accepts_sample (const struct dds_rhc_default *rhc, const struct
|
|||
return 0;
|
||||
}
|
||||
}
|
||||
if (rhc->exclusive_ownership && inst->wr_iid_islive && inst->wr_iid != pwr_info->iid)
|
||||
if (rhc->exclusive_ownership && inst->wr_iid_islive && inst->wr_iid != wrinfo->iid)
|
||||
{
|
||||
int32_t strength = pwr_info->ownership_strength;
|
||||
int32_t strength = wrinfo->ownership_strength;
|
||||
if (strength > inst->strength) {
|
||||
/* ok */
|
||||
} else if (strength < inst->strength) {
|
||||
return 0;
|
||||
} else if (inst_accepts_sample_by_writer_guid (inst, pwr_info)) {
|
||||
} else if (inst_accepts_sample_by_writer_guid (inst, wrinfo)) {
|
||||
/* ok */
|
||||
} else {
|
||||
return 0;
|
||||
|
@ -913,17 +920,17 @@ static int inst_accepts_sample (const struct dds_rhc_default *rhc, const struct
|
|||
return 1;
|
||||
}
|
||||
|
||||
static void update_inst (struct rhc_instance *inst, const struct proxy_writer_info * __restrict pwr_info, bool wr_iid_valid, nn_wctime_t tstamp)
|
||||
static void update_inst (struct rhc_instance *inst, const struct ddsi_writer_info * __restrict wrinfo, bool wr_iid_valid, nn_wctime_t tstamp)
|
||||
{
|
||||
inst->tstamp = tstamp;
|
||||
inst->wr_iid_islive = wr_iid_valid;
|
||||
if (wr_iid_valid)
|
||||
{
|
||||
inst->wr_iid = pwr_info->iid;
|
||||
if (inst->wr_iid != pwr_info->iid)
|
||||
inst->wr_guid = pwr_info->guid;
|
||||
inst->wr_iid = wrinfo->iid;
|
||||
if (inst->wr_iid != wrinfo->iid)
|
||||
inst->wr_guid = wrinfo->guid;
|
||||
}
|
||||
inst->strength = pwr_info->ownership_strength;
|
||||
inst->strength = wrinfo->ownership_strength;
|
||||
}
|
||||
|
||||
static void drop_instance_noupdate_no_writers (struct dds_rhc_default *rhc, struct rhc_instance *inst)
|
||||
|
@ -1109,13 +1116,13 @@ static int rhc_unregister_isreg_w_sideeffects (struct dds_rhc_default *rhc, cons
|
|||
}
|
||||
}
|
||||
|
||||
static int rhc_unregister_updateinst (struct dds_rhc_default *rhc, struct rhc_instance *inst, const struct proxy_writer_info * __restrict pwr_info, nn_wctime_t tstamp, struct trigger_info_qcond *trig_qc, bool *nda)
|
||||
static int rhc_unregister_updateinst (struct dds_rhc_default *rhc, struct rhc_instance *inst, const struct ddsi_writer_info * __restrict wrinfo, nn_wctime_t tstamp, struct trigger_info_qcond *trig_qc, bool *nda)
|
||||
{
|
||||
assert (inst->wrcount > 0);
|
||||
|
||||
if (--inst->wrcount > 0)
|
||||
{
|
||||
if (inst->wr_iid_islive && pwr_info->iid == inst->wr_iid)
|
||||
if (inst->wr_iid_islive && wrinfo->iid == inst->wr_iid)
|
||||
{
|
||||
/* Next register will have to do real work before we have a cached
|
||||
wr_iid again */
|
||||
|
@ -1142,7 +1149,7 @@ static int rhc_unregister_updateinst (struct dds_rhc_default *rhc, struct rhc_in
|
|||
if (inst->latest == NULL || inst->latest->isread)
|
||||
{
|
||||
inst_set_invsample (rhc, inst, trig_qc, nda);
|
||||
update_inst (inst, pwr_info, false, tstamp);
|
||||
update_inst (inst, wrinfo, false, tstamp);
|
||||
}
|
||||
if (!inst->isdisposed)
|
||||
{
|
||||
|
@ -1164,7 +1171,7 @@ static int rhc_unregister_updateinst (struct dds_rhc_default *rhc, struct rhc_in
|
|||
TRACE (",#0,empty,nowriters");
|
||||
assert (inst_is_empty (inst));
|
||||
inst_set_invsample (rhc, inst, trig_qc, nda);
|
||||
update_inst (inst, pwr_info, false, tstamp);
|
||||
update_inst (inst, wrinfo, false, tstamp);
|
||||
account_for_empty_to_nonempty_transition (rhc, inst);
|
||||
inst->wr_iid_islive = 0;
|
||||
return 0;
|
||||
|
@ -1172,18 +1179,18 @@ static int rhc_unregister_updateinst (struct dds_rhc_default *rhc, struct rhc_in
|
|||
}
|
||||
}
|
||||
|
||||
static bool dds_rhc_unregister (struct dds_rhc_default *rhc, struct rhc_instance *inst, const struct proxy_writer_info * __restrict pwr_info, nn_wctime_t tstamp, struct trigger_info_post *post, struct trigger_info_qcond *trig_qc)
|
||||
static bool dds_rhc_unregister (struct dds_rhc_default *rhc, struct rhc_instance *inst, const struct ddsi_writer_info * __restrict wrinfo, nn_wctime_t tstamp, struct trigger_info_post *post, struct trigger_info_qcond *trig_qc)
|
||||
{
|
||||
bool notify_data_available = false;
|
||||
|
||||
/* 'post' always gets set; instance may have been freed upon return. */
|
||||
TRACE (" unregister:");
|
||||
if (!rhc_unregister_isreg_w_sideeffects (rhc, inst, pwr_info->iid))
|
||||
if (!rhc_unregister_isreg_w_sideeffects (rhc, inst, wrinfo->iid))
|
||||
{
|
||||
/* other registrations remain */
|
||||
get_trigger_info_cmn (&post->c, inst);
|
||||
}
|
||||
else if (rhc_unregister_updateinst (rhc, inst, pwr_info, tstamp, trig_qc, ¬ify_data_available))
|
||||
else if (rhc_unregister_updateinst (rhc, inst, wrinfo, tstamp, trig_qc, ¬ify_data_available))
|
||||
{
|
||||
/* instance dropped */
|
||||
init_trigger_info_cmn_nonmatch (&post->c);
|
||||
|
@ -1196,7 +1203,7 @@ static bool dds_rhc_unregister (struct dds_rhc_default *rhc, struct rhc_instance
|
|||
return notify_data_available;
|
||||
}
|
||||
|
||||
static struct rhc_instance *alloc_new_instance (const struct dds_rhc_default *rhc, const struct proxy_writer_info *pwr_info, struct ddsi_serdata *serdata, struct ddsi_tkmap_instance *tk)
|
||||
static struct rhc_instance *alloc_new_instance (const struct dds_rhc_default *rhc, const struct ddsi_writer_info *wrinfo, struct ddsi_serdata *serdata, struct ddsi_tkmap_instance *tk)
|
||||
{
|
||||
struct rhc_instance *inst;
|
||||
|
||||
|
@ -1210,11 +1217,11 @@ static struct rhc_instance *alloc_new_instance (const struct dds_rhc_default *rh
|
|||
inst->isnew = 1;
|
||||
inst->a_sample_free = 1;
|
||||
inst->conds = 0;
|
||||
inst->wr_iid = pwr_info->iid;
|
||||
inst->wr_iid = wrinfo->iid;
|
||||
inst->wr_iid_islive = (inst->wrcount != 0);
|
||||
inst->wr_guid = pwr_info->guid;
|
||||
inst->wr_guid = wrinfo->guid;
|
||||
inst->tstamp = serdata->timestamp;
|
||||
inst->strength = pwr_info->ownership_strength;
|
||||
inst->strength = wrinfo->ownership_strength;
|
||||
|
||||
if (rhc->nqconds != 0)
|
||||
{
|
||||
|
@ -1230,7 +1237,7 @@ static struct rhc_instance *alloc_new_instance (const struct dds_rhc_default *rh
|
|||
return inst;
|
||||
}
|
||||
|
||||
static rhc_store_result_t rhc_store_new_instance (struct rhc_instance **out_inst, struct dds_rhc_default *rhc, const struct proxy_writer_info *pwr_info, struct ddsi_serdata *sample, struct ddsi_tkmap_instance *tk, const bool has_data, status_cb_data_t *cb_data, struct trigger_info_post *post, struct trigger_info_qcond *trig_qc)
|
||||
static rhc_store_result_t rhc_store_new_instance (struct rhc_instance **out_inst, struct dds_rhc_default *rhc, const struct ddsi_writer_info *wrinfo, struct ddsi_serdata *sample, struct ddsi_tkmap_instance *tk, const bool has_data, status_cb_data_t *cb_data, struct trigger_info_post *post, struct trigger_info_qcond *trig_qc)
|
||||
{
|
||||
struct rhc_instance *inst;
|
||||
int ret;
|
||||
|
@ -1265,10 +1272,10 @@ static rhc_store_result_t rhc_store_new_instance (struct rhc_instance **out_inst
|
|||
return RHC_REJECTED;
|
||||
}
|
||||
|
||||
inst = alloc_new_instance (rhc, pwr_info, sample, tk);
|
||||
inst = alloc_new_instance (rhc, wrinfo, sample, tk);
|
||||
if (has_data)
|
||||
{
|
||||
if (!add_sample (rhc, inst, pwr_info, sample, cb_data, trig_qc))
|
||||
if (!add_sample (rhc, inst, wrinfo, sample, cb_data, trig_qc))
|
||||
{
|
||||
free_empty_instance (inst, rhc);
|
||||
return RHC_REJECTED;
|
||||
|
@ -1298,9 +1305,9 @@ static rhc_store_result_t rhc_store_new_instance (struct rhc_instance **out_inst
|
|||
delivered (true unless a reliable sample rejected).
|
||||
*/
|
||||
|
||||
static bool dds_rhc_default_store (struct dds_rhc_default * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info, struct ddsi_serdata * __restrict sample, struct ddsi_tkmap_instance * __restrict tk)
|
||||
static bool dds_rhc_default_store (struct dds_rhc_default * __restrict rhc, const struct ddsi_writer_info * __restrict wrinfo, struct ddsi_serdata * __restrict sample, struct ddsi_tkmap_instance * __restrict tk)
|
||||
{
|
||||
const uint64_t wr_iid = pwr_info->iid;
|
||||
const uint64_t wr_iid = wrinfo->iid;
|
||||
const unsigned statusinfo = sample->statusinfo;
|
||||
const bool has_data = (sample->kind == SDK_DATA);
|
||||
const int is_dispose = (statusinfo & NN_STATUSINFO_DISPOSE) != 0;
|
||||
|
@ -1347,7 +1354,7 @@ static bool dds_rhc_default_store (struct dds_rhc_default * __restrict rhc, cons
|
|||
else
|
||||
{
|
||||
TRACE (" new instance");
|
||||
stored = rhc_store_new_instance (&inst, rhc, pwr_info, sample, tk, has_data, &cb_data, &post, &trig_qc);
|
||||
stored = rhc_store_new_instance (&inst, rhc, wrinfo, sample, tk, has_data, &cb_data, &post, &trig_qc);
|
||||
if (stored != RHC_STORED)
|
||||
{
|
||||
goto error_or_nochange;
|
||||
|
@ -1356,7 +1363,7 @@ static bool dds_rhc_default_store (struct dds_rhc_default * __restrict rhc, cons
|
|||
notify_data_available = true;
|
||||
}
|
||||
}
|
||||
else if (!inst_accepts_sample (rhc, inst, pwr_info, sample, has_data))
|
||||
else if (!inst_accepts_sample (rhc, inst, wrinfo, sample, has_data))
|
||||
{
|
||||
/* Rejected samples (and disposes) should still register the writer;
|
||||
unregister *must* be processed, or we have a memory leak. (We
|
||||
|
@ -1372,7 +1379,7 @@ static bool dds_rhc_default_store (struct dds_rhc_default * __restrict rhc, cons
|
|||
}
|
||||
if (statusinfo & NN_STATUSINFO_UNREGISTER)
|
||||
{
|
||||
if (dds_rhc_unregister (rhc, inst, pwr_info, sample->timestamp, &post, &trig_qc))
|
||||
if (dds_rhc_unregister (rhc, inst, wrinfo, sample->timestamp, &post, &trig_qc))
|
||||
notify_data_available = true;
|
||||
}
|
||||
else
|
||||
|
@ -1450,7 +1457,7 @@ static bool dds_rhc_default_store (struct dds_rhc_default * __restrict rhc, cons
|
|||
if (has_data)
|
||||
{
|
||||
TRACE (" add_sample");
|
||||
if (!add_sample (rhc, inst, pwr_info, sample, &cb_data, &trig_qc))
|
||||
if (!add_sample (rhc, inst, wrinfo, sample, &cb_data, &trig_qc))
|
||||
{
|
||||
TRACE ("(reject)");
|
||||
stored = RHC_REJECTED;
|
||||
|
@ -1469,7 +1476,7 @@ static bool dds_rhc_default_store (struct dds_rhc_default * __restrict rhc, cons
|
|||
if (inst_became_disposed && inst->latest == NULL)
|
||||
inst_set_invsample (rhc, inst, &trig_qc, ¬ify_data_available);
|
||||
|
||||
update_inst (inst, pwr_info, true, sample->timestamp);
|
||||
update_inst (inst, wrinfo, true, sample->timestamp);
|
||||
|
||||
/* Can only add samples => only need to give special treatment
|
||||
to instances that were empty before. It is, however, not
|
||||
|
@ -1513,7 +1520,7 @@ static bool dds_rhc_default_store (struct dds_rhc_default * __restrict rhc, cons
|
|||
mean an application reading "x" after the write and reading it
|
||||
again after the unregister will see a change in the
|
||||
no_writers_generation field? */
|
||||
dds_rhc_unregister (rhc, inst, pwr_info, sample->timestamp, &post, &trig_qc);
|
||||
dds_rhc_unregister (rhc, inst, wrinfo, sample->timestamp, &post, &trig_qc);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1559,7 +1566,7 @@ error_or_nochange:
|
|||
return delivered;
|
||||
}
|
||||
|
||||
static void dds_rhc_default_unregister_wr (struct dds_rhc_default * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info)
|
||||
static void dds_rhc_default_unregister_wr (struct dds_rhc_default * __restrict rhc, const struct ddsi_writer_info * __restrict wrinfo)
|
||||
{
|
||||
/* Only to be called when writer with ID WR_IID has died.
|
||||
|
||||
|
@ -1579,8 +1586,8 @@ static void dds_rhc_default_unregister_wr (struct dds_rhc_default * __restrict r
|
|||
bool notify_data_available = false;
|
||||
struct rhc_instance *inst;
|
||||
struct ddsrt_hh_iter iter;
|
||||
const uint64_t wr_iid = pwr_info->iid;
|
||||
const int auto_dispose = pwr_info->auto_dispose;
|
||||
const uint64_t wr_iid = wrinfo->iid;
|
||||
const int auto_dispose = wrinfo->auto_dispose;
|
||||
|
||||
size_t ntriggers = SIZE_MAX;
|
||||
|
||||
|
@ -1620,7 +1627,7 @@ static void dds_rhc_default_unregister_wr (struct dds_rhc_default * __restrict r
|
|||
}
|
||||
}
|
||||
|
||||
dds_rhc_unregister (rhc, inst, pwr_info, inst->tstamp, &post, &trig_qc);
|
||||
dds_rhc_unregister (rhc, inst, wrinfo, inst->tstamp, &post, &trig_qc);
|
||||
|
||||
TRACE ("\n");
|
||||
|
||||
|
@ -2292,13 +2299,12 @@ static bool cond_is_sample_state_dependent (const struct dds_readcond *cond)
|
|||
}
|
||||
}
|
||||
|
||||
static bool dds_rhc_default_add_readcondition (dds_readcond *cond)
|
||||
static bool dds_rhc_default_add_readcondition (struct dds_rhc_default *rhc, dds_readcond *cond)
|
||||
{
|
||||
/* On the assumption that a readcondition will be attached to a
|
||||
waitset for nearly all of its life, we keep track of all
|
||||
readconditions on a reader in one set, without distinguishing
|
||||
between those attached to a waitset or not. */
|
||||
struct dds_rhc_default *rhc = (struct dds_rhc_default *) cond->m_rhc;
|
||||
struct ddsrt_hh_iter it;
|
||||
|
||||
assert ((dds_entity_kind (&cond->m_entity) == DDS_KIND_COND_READ && cond->m_query.m_filter == 0) ||
|
||||
|
@ -2397,9 +2403,8 @@ static bool dds_rhc_default_add_readcondition (dds_readcond *cond)
|
|||
return true;
|
||||
}
|
||||
|
||||
static void dds_rhc_default_remove_readcondition (dds_readcond *cond)
|
||||
static void dds_rhc_default_remove_readcondition (struct dds_rhc_default *rhc, dds_readcond *cond)
|
||||
{
|
||||
struct dds_rhc_default *rhc = (struct dds_rhc_default *) cond->m_rhc;
|
||||
dds_readcond **ptr;
|
||||
ddsrt_mutex_lock (&rhc->lock);
|
||||
ptr = &rhc->conds;
|
||||
|
|
|
@ -32,7 +32,7 @@ static const uint64_t unihashconsts[] = {
|
|||
UINT64_C (16728792139623414127)
|
||||
};
|
||||
|
||||
static uint32_t hash_guid (const nn_guid_t *g)
|
||||
static uint32_t hash_guid (const ddsi_guid_t *g)
|
||||
{
|
||||
return
|
||||
(uint32_t) (((((uint32_t) g->prefix.u[0] + unihashconsts[0]) *
|
||||
|
@ -131,7 +131,7 @@ static struct ddsi_serdata *ddsi_serdata_builtin_from_keyhash (const struct ddsi
|
|||
/* FIXME: not quite elegant to manage the creation of a serdata for a built-in topic via this function, but I also find it quite unelegant to let from_sample read straight from the underlying internal entity, and to_sample convert to the external format ... I could claim the internal entity is the "serialised form", but that forces wrapping it in a fragchain in one way or another, which, though possible, is also a bit lacking in elegance. */
|
||||
const struct ddsi_sertopic_builtintopic *tp = (const struct ddsi_sertopic_builtintopic *)tpcmn;
|
||||
/* keyhash must in host format (which the GUIDs always are internally) */
|
||||
struct entity_common *entity = ephash_lookup_guid_untyped (tp->gv->guid_hash, (const nn_guid_t *) keyhash->value);
|
||||
struct entity_common *entity = ephash_lookup_guid_untyped (tp->gv->guid_hash, (const ddsi_guid_t *) keyhash->value);
|
||||
struct ddsi_serdata_builtintopic *d = serdata_builtin_new(tp, entity ? SDK_DATA : SDK_KEY);
|
||||
memcpy (&d->key, keyhash->value, sizeof (d->key));
|
||||
if (entity)
|
||||
|
@ -175,9 +175,9 @@ static struct ddsi_serdata *serdata_builtin_to_topicless (const struct ddsi_serd
|
|||
return ddsi_serdata_ref (serdata_common);
|
||||
}
|
||||
|
||||
static void convkey (dds_builtintopic_guid_t *key, const nn_guid_t *guid)
|
||||
static void convkey (dds_builtintopic_guid_t *key, const ddsi_guid_t *guid)
|
||||
{
|
||||
nn_guid_t tmp;
|
||||
ddsi_guid_t tmp;
|
||||
tmp = nn_hton_guid (*guid);
|
||||
memcpy (key, &tmp, sizeof (*key));
|
||||
}
|
||||
|
@ -214,7 +214,7 @@ static bool to_sample_pp (const struct ddsi_serdata_builtintopic *d, struct dds_
|
|||
|
||||
static bool to_sample_endpoint (const struct ddsi_serdata_builtintopic *d, struct dds_builtintopic_endpoint *sample)
|
||||
{
|
||||
nn_guid_t ppguid;
|
||||
ddsi_guid_t ppguid;
|
||||
convkey (&sample->key, &d->key);
|
||||
ppguid = d->key;
|
||||
ppguid.entityid.u = NN_ENTITYID_PARTICIPANT;
|
||||
|
@ -276,6 +276,12 @@ static void serdata_builtin_to_ser_unref (struct ddsi_serdata *serdata_common, c
|
|||
(void)serdata_common; (void)ref;
|
||||
}
|
||||
|
||||
static size_t serdata_builtin_topic_print (const struct ddsi_sertopic *topic, const struct ddsi_serdata *serdata_common, char *buf, size_t size)
|
||||
{
|
||||
(void)topic; (void)serdata_common;
|
||||
return (size_t) snprintf (buf, size, "(blob)");
|
||||
}
|
||||
|
||||
const struct ddsi_serdata_ops ddsi_serdata_ops_builtintopic = {
|
||||
.get_size = serdata_builtin_get_size,
|
||||
.eqkey = serdata_builtin_eqkey,
|
||||
|
@ -288,5 +294,6 @@ const struct ddsi_serdata_ops ddsi_serdata_ops_builtintopic = {
|
|||
.to_ser_ref = serdata_builtin_to_ser_ref,
|
||||
.to_ser_unref = serdata_builtin_to_ser_unref,
|
||||
.to_topicless = serdata_builtin_to_topicless,
|
||||
.topicless_to_sample = serdata_builtin_topicless_to_sample
|
||||
.topicless_to_sample = serdata_builtin_topicless_to_sample,
|
||||
.print = serdata_builtin_topic_print
|
||||
};
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
*/
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "dds/ddsrt/endian.h"
|
||||
#include "dds/ddsrt/md5.h"
|
||||
|
@ -1608,6 +1609,292 @@ void dds_stream_extract_keyhash (dds_istream_t * __restrict is, dds_keyhash_t *
|
|||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************************
|
||||
**
|
||||
** Pretty-printing
|
||||
**
|
||||
*******************************************************************************************/
|
||||
|
||||
/* Returns true if buffer not yet exhausted, false otherwise */
|
||||
static bool prtf (char * __restrict *buf, size_t * __restrict bufsize, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
if (*bufsize == 0)
|
||||
return false;
|
||||
va_start (ap, fmt);
|
||||
int n = vsnprintf (*buf, *bufsize, fmt, ap);
|
||||
va_end (ap);
|
||||
if (n < 0)
|
||||
{
|
||||
**buf = 0;
|
||||
return false;
|
||||
}
|
||||
else if ((size_t) n <= *bufsize)
|
||||
{
|
||||
*buf += (size_t) n;
|
||||
*bufsize -= (size_t) n;
|
||||
return (*bufsize > 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
*buf += *bufsize;
|
||||
*bufsize = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool prtf_str (char * __restrict *buf, size_t * __restrict bufsize, dds_istream_t * __restrict is)
|
||||
{
|
||||
size_t sz = dds_is_get4 (is);
|
||||
bool ret = prtf (buf, bufsize, "\"%s\"", is->m_buffer + is->m_index);
|
||||
is->m_index += (uint32_t) sz;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static size_t isprint_runlen (const unsigned char *s, size_t n)
|
||||
{
|
||||
size_t m;
|
||||
for (m = 0; m < n && s[m] != '"' && isprint (s[m]); m++)
|
||||
;
|
||||
return m;
|
||||
}
|
||||
|
||||
static bool prtf_simple (char * __restrict *buf, size_t * __restrict bufsize, dds_istream_t * __restrict is, enum dds_stream_typecode type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case DDS_OP_VAL_1BY: return prtf (buf, bufsize, "%"PRIu8, dds_is_get1 (is));
|
||||
case DDS_OP_VAL_2BY: return prtf (buf, bufsize, "%"PRIu16, dds_is_get2 (is));
|
||||
case DDS_OP_VAL_4BY: return prtf (buf, bufsize, "%"PRIu32, dds_is_get4 (is));
|
||||
case DDS_OP_VAL_8BY: return prtf (buf, bufsize, "%"PRIu64, dds_is_get8 (is));
|
||||
case DDS_OP_VAL_STR: case DDS_OP_VAL_BST: return prtf_str (buf, bufsize, is);
|
||||
case DDS_OP_VAL_ARR: case DDS_OP_VAL_SEQ: case DDS_OP_VAL_UNI: case DDS_OP_VAL_STU:
|
||||
abort ();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool prtf_simple_array (char * __restrict *buf, size_t * __restrict bufsize, dds_istream_t * __restrict is, uint32_t num, enum dds_stream_typecode type)
|
||||
{
|
||||
bool cont = prtf (buf, bufsize, "{");
|
||||
switch (type)
|
||||
{
|
||||
case DDS_OP_VAL_1BY: {
|
||||
size_t i = 0, j;
|
||||
while (cont && i < num)
|
||||
{
|
||||
size_t m = isprint_runlen ((unsigned char *) (is->m_buffer + is->m_index), num - i);
|
||||
if (m >= 4)
|
||||
{
|
||||
cont = prtf (buf, bufsize, "%s\"", i != 0 ? "," : "");
|
||||
for (j = 0; cont && j < m; j++)
|
||||
cont = prtf (buf, bufsize, "%c", is->m_buffer[is->m_index + j]);
|
||||
cont = prtf (buf, bufsize, "\"");
|
||||
is->m_index += (uint32_t) m;
|
||||
i += m;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (i != 0)
|
||||
(void) prtf (buf, bufsize, ",");
|
||||
cont = prtf_simple (buf, bufsize, is, type);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DDS_OP_VAL_2BY: case DDS_OP_VAL_4BY: case DDS_OP_VAL_8BY:
|
||||
case DDS_OP_VAL_STR: case DDS_OP_VAL_BST:
|
||||
for (size_t i = 0; cont && i < num; i++)
|
||||
{
|
||||
if (i != 0)
|
||||
(void) prtf (buf, bufsize, ",");
|
||||
cont = prtf_simple (buf, bufsize, is, type);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
abort ();
|
||||
break;
|
||||
}
|
||||
return cont;
|
||||
}
|
||||
|
||||
static bool dds_stream_print_sample1 (char * __restrict *buf, size_t * __restrict bufsize, dds_istream_t * __restrict is, const uint32_t * __restrict ops, bool add_braces);
|
||||
|
||||
static const uint32_t *prtf_seq (char * __restrict *buf, size_t *bufsize, dds_istream_t * __restrict is, const uint32_t * __restrict ops, uint32_t insn)
|
||||
{
|
||||
const enum dds_stream_typecode subtype = DDS_OP_SUBTYPE (insn);
|
||||
uint32_t num;
|
||||
num = dds_is_get4 (is);
|
||||
if (num == 0)
|
||||
{
|
||||
prtf (buf, bufsize, "{}");
|
||||
return skip_sequence_insns (ops, insn);
|
||||
}
|
||||
switch (subtype)
|
||||
{
|
||||
case DDS_OP_VAL_1BY: case DDS_OP_VAL_2BY: case DDS_OP_VAL_4BY: case DDS_OP_VAL_8BY:
|
||||
prtf_simple_array (buf, bufsize, is, num, subtype);
|
||||
return ops + 2;
|
||||
case DDS_OP_VAL_STR: case DDS_OP_VAL_BST:
|
||||
prtf_simple_array (buf, bufsize, is, num, subtype);
|
||||
return ops + (subtype == DDS_OP_VAL_STR ? 2 : 3);
|
||||
case DDS_OP_VAL_SEQ: case DDS_OP_VAL_ARR: case DDS_OP_VAL_UNI: case DDS_OP_VAL_STU: {
|
||||
const uint32_t jmp = DDS_OP_ADR_JMP (ops[3]);
|
||||
uint32_t const * const jsr_ops = ops + DDS_OP_ADR_JSR (ops[3]);
|
||||
bool cont = prtf (buf, bufsize, "{");
|
||||
for (uint32_t i = 0; cont && i < num; i++)
|
||||
{
|
||||
if (i > 0) prtf (buf, bufsize, ",");
|
||||
cont = dds_stream_print_sample1 (buf, bufsize, is, jsr_ops, subtype == DDS_OP_VAL_STU);
|
||||
}
|
||||
prtf (buf, bufsize, "}");
|
||||
return ops + (jmp ? jmp : 4); /* FIXME: why would jmp be 0? */
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const uint32_t *prtf_arr (char * __restrict *buf, size_t *bufsize, dds_istream_t * __restrict is, const uint32_t * __restrict ops, uint32_t insn)
|
||||
{
|
||||
const enum dds_stream_typecode subtype = DDS_OP_SUBTYPE (insn);
|
||||
const uint32_t num = ops[2];
|
||||
switch (subtype)
|
||||
{
|
||||
case DDS_OP_VAL_1BY: case DDS_OP_VAL_2BY: case DDS_OP_VAL_4BY: case DDS_OP_VAL_8BY:
|
||||
prtf_simple_array (buf, bufsize, is, num, subtype);
|
||||
return ops + 3;
|
||||
case DDS_OP_VAL_STR: case DDS_OP_VAL_BST:
|
||||
prtf_simple_array (buf, bufsize, is, num, subtype);
|
||||
return ops + (subtype == DDS_OP_VAL_STR ? 3 : 5);
|
||||
case DDS_OP_VAL_SEQ: case DDS_OP_VAL_ARR: case DDS_OP_VAL_UNI: case DDS_OP_VAL_STU: {
|
||||
const uint32_t *jsr_ops = ops + DDS_OP_ADR_JSR (ops[3]);
|
||||
const uint32_t jmp = DDS_OP_ADR_JMP (ops[3]);
|
||||
bool cont = prtf (buf, bufsize, "{");
|
||||
for (uint32_t i = 0; cont && i < num; i++)
|
||||
{
|
||||
if (i > 0) prtf (buf, bufsize, ",");
|
||||
cont = dds_stream_print_sample1 (buf, bufsize, is, jsr_ops, subtype == DDS_OP_VAL_STU);
|
||||
}
|
||||
prtf (buf, bufsize, "}");
|
||||
return ops + (jmp ? jmp : 5);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const uint32_t *prtf_uni (char * __restrict *buf, size_t *bufsize, dds_istream_t * __restrict is, const uint32_t * __restrict ops, uint32_t insn)
|
||||
{
|
||||
const uint32_t disc = read_union_discriminant (is, DDS_OP_SUBTYPE (insn));
|
||||
uint32_t const * const jeq_op = find_union_case (ops, disc);
|
||||
prtf (buf, bufsize, "%"PRIu32":", disc);
|
||||
ops += DDS_OP_ADR_JMP (ops[3]);
|
||||
if (jeq_op)
|
||||
{
|
||||
const enum dds_stream_typecode valtype = DDS_JEQ_TYPE (jeq_op[0]);
|
||||
switch (valtype)
|
||||
{
|
||||
case DDS_OP_VAL_1BY: case DDS_OP_VAL_2BY: case DDS_OP_VAL_4BY: case DDS_OP_VAL_8BY:
|
||||
case DDS_OP_VAL_STR: case DDS_OP_VAL_BST:
|
||||
prtf_simple (buf, bufsize, is, valtype);
|
||||
break;
|
||||
case DDS_OP_VAL_SEQ: case DDS_OP_VAL_ARR: case DDS_OP_VAL_UNI: case DDS_OP_VAL_STU:
|
||||
dds_stream_print_sample1 (buf, bufsize, is, jeq_op + DDS_OP_ADR_JSR (jeq_op[0]), valtype == DDS_OP_VAL_STU);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ops;
|
||||
}
|
||||
|
||||
static bool dds_stream_print_sample1 (char * __restrict *buf, size_t * __restrict bufsize, dds_istream_t * __restrict is, const uint32_t * __restrict ops, bool add_braces)
|
||||
{
|
||||
uint32_t insn;
|
||||
bool cont = true;
|
||||
bool needs_comma = false;
|
||||
if (add_braces)
|
||||
prtf (buf, bufsize, "{");
|
||||
while (cont && (insn = *ops) != DDS_OP_RTS)
|
||||
{
|
||||
if (needs_comma)
|
||||
prtf (buf, bufsize, ",");
|
||||
needs_comma = true;
|
||||
switch (DDS_OP (insn))
|
||||
{
|
||||
case DDS_OP_ADR: {
|
||||
switch (DDS_OP_TYPE (insn))
|
||||
{
|
||||
case DDS_OP_VAL_1BY: case DDS_OP_VAL_2BY: case DDS_OP_VAL_4BY: case DDS_OP_VAL_8BY:
|
||||
case DDS_OP_VAL_STR:
|
||||
cont = prtf_simple (buf, bufsize, is, DDS_OP_TYPE (insn));
|
||||
ops += 2;
|
||||
break;
|
||||
case DDS_OP_VAL_BST:
|
||||
cont = prtf_simple (buf, bufsize, is, DDS_OP_TYPE (insn));
|
||||
ops += 3;
|
||||
break;
|
||||
case DDS_OP_VAL_SEQ:
|
||||
ops = prtf_seq (buf, bufsize, is, ops, insn);
|
||||
break;
|
||||
case DDS_OP_VAL_ARR:
|
||||
ops = prtf_arr (buf, bufsize, is, ops, insn);
|
||||
break;
|
||||
case DDS_OP_VAL_UNI:
|
||||
ops = prtf_uni (buf, bufsize, is, ops, insn);
|
||||
break;
|
||||
case DDS_OP_VAL_STU:
|
||||
abort ();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DDS_OP_JSR: {
|
||||
cont = dds_stream_print_sample1 (buf, bufsize, is, ops + DDS_OP_JUMP (insn), true);
|
||||
ops++;
|
||||
break;
|
||||
}
|
||||
case DDS_OP_RTS: case DDS_OP_JEQ: {
|
||||
abort ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (add_braces)
|
||||
prtf (buf, bufsize, "}");
|
||||
return cont;
|
||||
}
|
||||
|
||||
size_t dds_stream_print_sample (dds_istream_t * __restrict is, const struct ddsi_sertopic_default * __restrict topic, char * __restrict buf, size_t bufsize)
|
||||
{
|
||||
dds_stream_print_sample1 (&buf, &bufsize, is, topic->type->m_ops, true);
|
||||
return bufsize;
|
||||
}
|
||||
|
||||
size_t dds_stream_print_key (dds_istream_t * __restrict is, const struct ddsi_sertopic_default * __restrict topic, char * __restrict buf, size_t bufsize)
|
||||
{
|
||||
const dds_topic_descriptor_t *desc = topic->type;
|
||||
bool cont = prtf (&buf, &bufsize, ":k:{");
|
||||
for (uint32_t i = 0; cont && i < desc->m_nkeys; i++)
|
||||
{
|
||||
const uint32_t *op = desc->m_ops + desc->m_keys[i].m_index;
|
||||
assert (insn_key_ok_p (*op));
|
||||
switch (DDS_OP_TYPE (*op))
|
||||
{
|
||||
case DDS_OP_VAL_1BY: case DDS_OP_VAL_2BY: case DDS_OP_VAL_4BY: case DDS_OP_VAL_8BY:
|
||||
case DDS_OP_VAL_STR: case DDS_OP_VAL_BST:
|
||||
cont = prtf_simple (&buf, &bufsize, is, DDS_OP_TYPE (*op));
|
||||
break;
|
||||
case DDS_OP_VAL_ARR:
|
||||
cont = prtf_simple_array (&buf, &bufsize, is, op[2], DDS_OP_SUBTYPE (*op));
|
||||
break;
|
||||
case DDS_OP_VAL_SEQ: case DDS_OP_VAL_UNI: case DDS_OP_VAL_STU:
|
||||
abort ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
prtf (&buf, &bufsize, "}");
|
||||
return bufsize;
|
||||
}
|
||||
|
||||
/*******************************************************************************************
|
||||
**
|
||||
** Stuff to make it possible to treat a ddsi_serdata_default as a stream
|
||||
|
|
|
@ -38,6 +38,7 @@ static dds_return_t dds_subscriber_status_validate (uint32_t mask)
|
|||
}
|
||||
|
||||
const struct dds_entity_deriver dds_entity_deriver_subscriber = {
|
||||
.interrupt = dds_entity_deriver_dummy_interrupt,
|
||||
.close = dds_entity_deriver_dummy_close,
|
||||
.delete = dds_entity_deriver_dummy_delete,
|
||||
.set_qos = dds_subscriber_qos_set,
|
||||
|
@ -66,6 +67,7 @@ dds_entity_t dds__create_subscriber_l (dds_participant *participant, const dds_q
|
|||
subscriber = dds_entity_init (&sub->m_entity, &participant->m_entity, DDS_KIND_SUBSCRIBER, new_qos, listener, DDS_SUBSCRIBER_STATUS_MASK);
|
||||
sub->m_entity.m_iid = ddsi_iid_gen ();
|
||||
dds_entity_register_child (&participant->m_entity, &sub->m_entity);
|
||||
dds_entity_init_complete (&sub->m_entity);
|
||||
return subscriber;
|
||||
}
|
||||
|
||||
|
|
|
@ -131,7 +131,7 @@ static bool dds_find_topic_check_and_add_ref (dds_entity_t participant, dds_enti
|
|||
return false;
|
||||
|
||||
bool ret;
|
||||
if (tp->m_entity.m_participant->m_hdllink.hdl != participant || strcmp (tp->m_stopic->name, name) != 0)
|
||||
if (dds_entity_participant (&tp->m_entity)->m_entity.m_hdllink.hdl != participant || strcmp (tp->m_stopic->name, name) != 0)
|
||||
ret = false;
|
||||
else
|
||||
{
|
||||
|
@ -243,7 +243,7 @@ static bool sertopic_equivalent (const struct ddsi_sertopic *a, const struct dds
|
|||
return true;
|
||||
}
|
||||
|
||||
static dds_return_t create_topic_topic_arbirary_check_sertopic (dds_entity_t participant, dds_entity_t topic, struct ddsi_sertopic *sertopic, const dds_qos_t *qos)
|
||||
static dds_return_t create_topic_topic_arbitrary_check_sertopic (dds_entity_t participant, dds_entity_t topic, struct ddsi_sertopic *sertopic, const dds_qos_t *qos)
|
||||
{
|
||||
dds_topic *tp;
|
||||
dds_return_t ret;
|
||||
|
@ -251,7 +251,7 @@ static dds_return_t create_topic_topic_arbirary_check_sertopic (dds_entity_t par
|
|||
if (dds_topic_lock (topic, &tp) < 0)
|
||||
return DDS_RETCODE_NOT_FOUND;
|
||||
|
||||
if (tp->m_entity.m_participant->m_hdllink.hdl != participant)
|
||||
if (dds_entity_participant (&tp->m_entity)->m_entity.m_hdllink.hdl != participant)
|
||||
ret = DDS_RETCODE_NOT_FOUND;
|
||||
else if (!sertopic_equivalent (tp->m_stopic, sertopic))
|
||||
ret = DDS_RETCODE_PRECONDITION_NOT_MET;
|
||||
|
@ -272,6 +272,7 @@ static dds_return_t create_topic_topic_arbirary_check_sertopic (dds_entity_t par
|
|||
}
|
||||
|
||||
const struct dds_entity_deriver dds_entity_deriver_topic = {
|
||||
.interrupt = dds_entity_deriver_dummy_interrupt,
|
||||
.close = dds_entity_deriver_dummy_close,
|
||||
.delete = dds_topic_delete,
|
||||
.set_qos = dds_topic_qos_set,
|
||||
|
@ -296,6 +297,14 @@ dds_entity_t dds_create_topic_arbitrary (dds_entity_t participant, struct ddsi_s
|
|||
existing topic's compatibility */
|
||||
if ((rc = dds_entity_pin (participant, &par_ent)) < 0)
|
||||
return rc;
|
||||
/* Verify that we've been given a participant, not strictly necessary
|
||||
because dds_participant_lock below checks it, but this is more
|
||||
obvious */
|
||||
if (dds_entity_kind (par_ent) != DDS_KIND_PARTICIPANT)
|
||||
{
|
||||
dds_entity_unpin (par_ent);
|
||||
return DDS_RETCODE_ILLEGAL_OPERATION;
|
||||
}
|
||||
|
||||
new_qos = dds_create_qos ();
|
||||
if (qos)
|
||||
|
@ -351,7 +360,7 @@ dds_entity_t dds_create_topic_arbitrary (dds_entity_t participant, struct ddsi_s
|
|||
for the various scary cases. */
|
||||
dds_participant_unlock (par);
|
||||
|
||||
rc = create_topic_topic_arbirary_check_sertopic (participant, topic, sertopic, new_qos);
|
||||
rc = create_topic_topic_arbitrary_check_sertopic (participant, topic, sertopic, new_qos);
|
||||
switch (rc)
|
||||
{
|
||||
case DDS_RETCODE_OK: /* duplicate definition */
|
||||
|
@ -439,6 +448,8 @@ dds_entity_t dds_create_topic_arbitrary (dds_entity_t participant, struct ddsi_s
|
|||
nn_plist_fini (&plist);
|
||||
}
|
||||
thread_state_asleep (lookup_thread_state ());
|
||||
|
||||
dds_entity_init_complete (&top->m_entity);
|
||||
dds_participant_unlock (par);
|
||||
dds_entity_unpin (par_ent);
|
||||
return hdl;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
|
||||
* Copyright(c) 2006 to 2019 ADLINK Technology Limited and others
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0 which is available at
|
||||
|
@ -17,11 +17,10 @@
|
|||
#include "dds__participant.h"
|
||||
#include "dds__querycond.h"
|
||||
#include "dds__readcond.h"
|
||||
#include "dds__rhc.h"
|
||||
#include "dds__init.h"
|
||||
#include "dds/ddsc/dds_rhc.h"
|
||||
#include "dds/ddsi/ddsi_iid.h"
|
||||
|
||||
DEFINE_ENTITY_LOCK_UNLOCK (static, dds_waitset, DDS_KIND_WAITSET)
|
||||
|
||||
static bool is_triggered (struct dds_entity *e)
|
||||
{
|
||||
bool t;
|
||||
|
@ -63,7 +62,7 @@ static dds_return_t dds_waitset_wait_impl (dds_entity_t waitset, dds_attach_t *x
|
|||
}
|
||||
|
||||
/* Move any previously but no longer triggering entities back to the observed list */
|
||||
ddsrt_mutex_lock (&ws->m_entity.m_mutex);
|
||||
ddsrt_mutex_lock (&ws->wait_lock);
|
||||
ws->ntriggered = 0;
|
||||
for (size_t i = 0; i < ws->nentities; i++)
|
||||
{
|
||||
|
@ -76,83 +75,195 @@ static dds_return_t dds_waitset_wait_impl (dds_entity_t waitset, dds_attach_t *x
|
|||
}
|
||||
|
||||
/* Only wait/keep waiting when we have something to observe and there aren't any triggers yet. */
|
||||
while (ws->nentities > 0 && ws->ntriggered == 0)
|
||||
if (!ddsrt_cond_waituntil (&ws->m_entity.m_cond, &ws->m_entity.m_mutex, abstimeout))
|
||||
while (ws->nentities > 0 && ws->ntriggered == 0 && !dds_handle_is_closed (&ws->m_entity.m_hdllink))
|
||||
if (!ddsrt_cond_waituntil (&ws->wait_cond, &ws->wait_lock, abstimeout))
|
||||
break;
|
||||
|
||||
ret = (int32_t) ws->ntriggered;
|
||||
for (size_t i = 0; i < ws->ntriggered && i < nxs; i++)
|
||||
xs[i] = ws->entities[i].arg;
|
||||
ddsrt_mutex_unlock (&ws->m_entity.m_mutex);
|
||||
ddsrt_mutex_unlock (&ws->wait_lock);
|
||||
dds_entity_unpin (&ws->m_entity);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static dds_return_t dds_waitset_close (struct dds_entity *e)
|
||||
static void dds_waitset_interrupt (struct dds_entity *e)
|
||||
{
|
||||
/* deep in the process of deleting the entity, so this is the only thread */
|
||||
dds_waitset *ws = (dds_waitset *) e;
|
||||
for (size_t i = 0; i < ws->nentities; i++)
|
||||
(void) dds_entity_observer_unregister (ws->entities[i].entity, &ws->m_entity);
|
||||
return DDS_RETCODE_OK;
|
||||
ddsrt_mutex_lock (&ws->wait_lock);
|
||||
assert (dds_handle_is_closed (&ws->m_entity.m_hdllink));
|
||||
ddsrt_cond_broadcast (&ws->wait_cond);
|
||||
ddsrt_mutex_unlock (&ws->wait_lock);
|
||||
}
|
||||
|
||||
static void dds_waitset_close (struct dds_entity *e)
|
||||
{
|
||||
dds_waitset *ws = (dds_waitset *) e;
|
||||
ddsrt_mutex_lock (&ws->wait_lock);
|
||||
while (ws->nentities > 0)
|
||||
{
|
||||
dds_entity *observed;
|
||||
if (dds_entity_pin (ws->entities[0].handle, &observed) < 0)
|
||||
{
|
||||
/* can't be pinned => being deleted => will be removed from wait set soon enough
|
||||
and go through delete_observer (which will trigger the condition variable) */
|
||||
ddsrt_cond_wait (&ws->wait_cond, &ws->wait_lock);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* entity will remain in existence */
|
||||
ddsrt_mutex_unlock (&ws->wait_lock);
|
||||
(void) dds_entity_observer_unregister (observed, ws, true);
|
||||
ddsrt_mutex_lock (&ws->wait_lock);
|
||||
assert (ws->nentities == 0 || ws->entities[0].entity != observed);
|
||||
dds_entity_unpin (observed);
|
||||
}
|
||||
}
|
||||
ddsrt_mutex_unlock (&ws->wait_lock);
|
||||
}
|
||||
|
||||
static dds_return_t dds_waitset_delete (struct dds_entity *e)
|
||||
{
|
||||
/* deep in the process of deleting the entity, so this is the only thread */
|
||||
dds_waitset *ws = (dds_waitset *) e;
|
||||
ddsrt_mutex_destroy (&ws->wait_lock);
|
||||
ddsrt_cond_destroy (&ws->wait_cond);
|
||||
ddsrt_free (ws->entities);
|
||||
return DDS_RETCODE_OK;
|
||||
}
|
||||
|
||||
const struct dds_entity_deriver dds_entity_deriver_waitset = {
|
||||
.interrupt = dds_waitset_interrupt,
|
||||
.close = dds_waitset_close,
|
||||
.delete = dds_waitset_delete,
|
||||
.set_qos = dds_entity_deriver_dummy_set_qos,
|
||||
.validate_status = dds_entity_deriver_dummy_validate_status
|
||||
};
|
||||
|
||||
dds_entity_t dds_create_waitset (dds_entity_t participant)
|
||||
dds_entity_t dds_create_waitset (dds_entity_t owner)
|
||||
{
|
||||
dds_entity_t hdl;
|
||||
dds_participant *par;
|
||||
dds_entity *e;
|
||||
dds_return_t rc;
|
||||
|
||||
if ((rc = dds_participant_lock (participant, &par)) != DDS_RETCODE_OK)
|
||||
/* If the owner is any ordinary (allowed) entity, the library is already initialised and calling
|
||||
init here is cheap. If it is DDS_CYCLONEDDS_HANDLE, we may have to initialise the library, so
|
||||
have to call it. If it is some bogus value and the library is not initialised yet ... so be
|
||||
it. Naturally, this requires us to call delete on DDS_CYCLONEDDS_HANDLE afterward. */
|
||||
if ((rc = dds_init ()) < 0)
|
||||
return rc;
|
||||
|
||||
if ((rc = dds_entity_lock (owner, DDS_KIND_DONTCARE, &e)) != DDS_RETCODE_OK)
|
||||
goto err_entity_lock;
|
||||
|
||||
switch (dds_entity_kind (e))
|
||||
{
|
||||
case DDS_KIND_CYCLONEDDS:
|
||||
case DDS_KIND_DOMAIN:
|
||||
case DDS_KIND_PARTICIPANT:
|
||||
break;
|
||||
default:
|
||||
rc = DDS_RETCODE_ILLEGAL_OPERATION;
|
||||
goto err_entity_kind;
|
||||
}
|
||||
|
||||
dds_waitset *waitset = dds_alloc (sizeof (*waitset));
|
||||
hdl = dds_entity_init (&waitset->m_entity, &par->m_entity, DDS_KIND_WAITSET, NULL, NULL, 0);
|
||||
dds_entity_t hdl = dds_entity_init (&waitset->m_entity, e, DDS_KIND_WAITSET, NULL, NULL, 0);
|
||||
ddsrt_mutex_init (&waitset->wait_lock);
|
||||
ddsrt_cond_init (&waitset->wait_cond);
|
||||
waitset->m_entity.m_iid = ddsi_iid_gen ();
|
||||
dds_entity_register_child (&par->m_entity, &waitset->m_entity);
|
||||
dds_entity_register_child (e, &waitset->m_entity);
|
||||
waitset->nentities = 0;
|
||||
waitset->ntriggered = 0;
|
||||
waitset->entities = NULL;
|
||||
dds_participant_unlock (par);
|
||||
dds_entity_init_complete (&waitset->m_entity);
|
||||
dds_entity_unlock (e);
|
||||
dds_delete_impl_pinned (&dds_global.m_entity, DIS_EXPLICIT);
|
||||
return hdl;
|
||||
|
||||
err_entity_kind:
|
||||
dds_entity_unlock (e);
|
||||
err_entity_lock:
|
||||
dds_delete_impl_pinned (&dds_global.m_entity, DIS_EXPLICIT);
|
||||
return rc;
|
||||
}
|
||||
|
||||
dds_return_t dds_waitset_get_entities (dds_entity_t waitset, dds_entity_t *entities, size_t size)
|
||||
{
|
||||
dds_return_t ret;
|
||||
dds_waitset *ws;
|
||||
|
||||
if ((ret = dds_waitset_lock (waitset, &ws)) != DDS_RETCODE_OK)
|
||||
dds_entity *wsent;
|
||||
if ((ret = dds_entity_pin (waitset, &wsent)) < 0)
|
||||
return ret;
|
||||
|
||||
if (entities != NULL)
|
||||
else if (dds_entity_kind (wsent) != DDS_KIND_WAITSET)
|
||||
{
|
||||
for (size_t i = 0; i < ws->nentities && i < size; i++)
|
||||
entities[i] = ws->entities[i].handle;
|
||||
dds_entity_unpin (wsent);
|
||||
return DDS_RETCODE_ILLEGAL_OPERATION;
|
||||
}
|
||||
else
|
||||
{
|
||||
dds_waitset *ws = (dds_waitset *) wsent;
|
||||
ddsrt_mutex_lock (&ws->wait_lock);
|
||||
if (entities != NULL)
|
||||
{
|
||||
for (size_t i = 0; i < ws->nentities && i < size; i++)
|
||||
entities[i] = ws->entities[i].handle;
|
||||
}
|
||||
ret = (int32_t) ws->nentities;
|
||||
ddsrt_mutex_unlock (&ws->wait_lock);
|
||||
dds_entity_unpin (&ws->m_entity);
|
||||
return ret;
|
||||
}
|
||||
ret = (int32_t) ws->nentities;
|
||||
dds_waitset_unlock (ws);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void dds_waitset_remove (dds_waitset *ws, dds_entity_t observed)
|
||||
/* This is called when the observed entity signals a status change. */
|
||||
static void dds_waitset_observer (struct dds_waitset *ws, dds_entity_t observed, uint32_t status)
|
||||
{
|
||||
(void) status;
|
||||
|
||||
ddsrt_mutex_lock (&ws->wait_lock);
|
||||
/* Move observed entity to triggered list. */
|
||||
size_t i;
|
||||
for (i = 0; i < ws->nentities; i++)
|
||||
if (ws->entities[i].handle == observed)
|
||||
break;
|
||||
if (i < ws->nentities && i >= ws->ntriggered)
|
||||
{
|
||||
dds_attachment tmp = ws->entities[i];
|
||||
ws->entities[i] = ws->entities[ws->ntriggered];
|
||||
ws->entities[ws->ntriggered++] = tmp;
|
||||
}
|
||||
/* Trigger waitset to wake up. */
|
||||
ddsrt_cond_broadcast (&ws->wait_cond);
|
||||
ddsrt_mutex_unlock (&ws->wait_lock);
|
||||
}
|
||||
|
||||
struct dds_waitset_attach_observer_arg {
|
||||
dds_attach_t x;
|
||||
};
|
||||
|
||||
static bool dds_waitset_attach_observer (struct dds_waitset *ws, struct dds_entity *observed, void *varg)
|
||||
{
|
||||
struct dds_waitset_attach_observer_arg *arg = varg;
|
||||
ddsrt_mutex_lock (&ws->wait_lock);
|
||||
ws->entities = ddsrt_realloc (ws->entities, (ws->nentities + 1) * sizeof (*ws->entities));
|
||||
ws->entities[ws->nentities].arg = arg->x;
|
||||
ws->entities[ws->nentities].entity = observed;
|
||||
ws->entities[ws->nentities].handle = observed->m_hdllink.hdl;
|
||||
ws->nentities++;
|
||||
if (is_triggered (observed))
|
||||
{
|
||||
const size_t i = ws->nentities - 1;
|
||||
dds_attachment tmp = ws->entities[i];
|
||||
ws->entities[i] = ws->entities[ws->ntriggered];
|
||||
ws->entities[ws->ntriggered++] = tmp;
|
||||
}
|
||||
ddsrt_cond_broadcast (&ws->wait_cond);
|
||||
ddsrt_mutex_unlock (&ws->wait_lock);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void dds_waitset_delete_observer (struct dds_waitset *ws, dds_entity_t observed)
|
||||
{
|
||||
size_t i;
|
||||
ddsrt_mutex_lock (&ws->wait_lock);
|
||||
for (i = 0; i < ws->nentities; i++)
|
||||
if (ws->entities[i].handle == observed)
|
||||
break;
|
||||
|
@ -167,118 +278,85 @@ static void dds_waitset_remove (dds_waitset *ws, dds_entity_t observed)
|
|||
{
|
||||
ws->entities[i] = ws->entities[--ws->nentities];
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* This is called when the observed entity signals a status change. */
|
||||
static void dds_waitset_observer (dds_entity *ent, dds_entity_t observed, uint32_t status)
|
||||
{
|
||||
assert (dds_entity_kind (ent) == DDS_KIND_WAITSET);
|
||||
dds_waitset *ws = (dds_waitset *) ent;
|
||||
(void) status;
|
||||
|
||||
ddsrt_mutex_lock (&ws->m_entity.m_mutex);
|
||||
/* Move observed entity to triggered list. */
|
||||
size_t i;
|
||||
for (i = 0; i < ws->nentities; i++)
|
||||
if (ws->entities[i].handle == observed)
|
||||
break;
|
||||
if (i < ws->nentities && i >= ws->ntriggered)
|
||||
{
|
||||
dds_attachment tmp = ws->entities[i];
|
||||
ws->entities[i] = ws->entities[ws->ntriggered];
|
||||
ws->entities[ws->ntriggered++] = tmp;
|
||||
}
|
||||
/* Trigger waitset to wake up. */
|
||||
ddsrt_cond_broadcast (&ws->m_entity.m_cond);
|
||||
ddsrt_mutex_unlock (&ws->m_entity.m_mutex);
|
||||
}
|
||||
|
||||
static void dds_waitset_delete_observer (dds_entity *ent, dds_entity_t observed)
|
||||
{
|
||||
assert (dds_entity_kind (ent) == DDS_KIND_WAITSET);
|
||||
dds_waitset *ws = (dds_waitset *) ent;
|
||||
ddsrt_mutex_lock (&ws->m_entity.m_mutex);
|
||||
/* Remove this observed entity, which is being deleted, from the waitset. */
|
||||
dds_waitset_remove (ws, observed);
|
||||
/* Our registration to this observed entity will be removed automatically. */
|
||||
/* Trigger waitset to wake up. */
|
||||
ddsrt_cond_broadcast (&ws->m_entity.m_cond);
|
||||
ddsrt_mutex_unlock (&ws->m_entity.m_mutex);
|
||||
ddsrt_cond_broadcast (&ws->wait_cond);
|
||||
ddsrt_mutex_unlock (&ws->wait_lock);
|
||||
}
|
||||
|
||||
dds_return_t dds_waitset_attach (dds_entity_t waitset, dds_entity_t entity, dds_attach_t x)
|
||||
{
|
||||
dds_entity *wsent;
|
||||
dds_entity *e;
|
||||
dds_waitset *ws;
|
||||
dds_return_t ret;
|
||||
|
||||
if ((ret = dds_waitset_lock (waitset, &ws)) < 0)
|
||||
if ((ret = dds_entity_pin (waitset, &wsent)) < 0)
|
||||
return ret;
|
||||
|
||||
if (waitset == entity)
|
||||
e = &ws->m_entity;
|
||||
else if ((ret = dds_entity_pin (entity, &e)) < 0)
|
||||
goto err_waitset;
|
||||
|
||||
/* This will fail if given entity is already attached (or deleted). */
|
||||
if ((ret = dds_entity_observer_register (e, &ws->m_entity, dds_waitset_observer, dds_waitset_delete_observer)) != DDS_RETCODE_OK)
|
||||
goto err_entity;
|
||||
|
||||
ws->entities = ddsrt_realloc (ws->entities, (ws->nentities + 1) * sizeof (*ws->entities));
|
||||
ws->entities[ws->nentities].arg = x;
|
||||
ws->entities[ws->nentities].entity = e;
|
||||
ws->entities[ws->nentities].handle = e->m_hdllink.hdl;
|
||||
ws->nentities++;
|
||||
if (is_triggered (e))
|
||||
else if (dds_entity_kind (wsent) != DDS_KIND_WAITSET)
|
||||
{
|
||||
const size_t i = ws->nentities - 1;
|
||||
dds_attachment tmp = ws->entities[i];
|
||||
ws->entities[i] = ws->entities[ws->ntriggered];
|
||||
ws->entities[ws->ntriggered++] = tmp;
|
||||
dds_entity_unpin (wsent);
|
||||
return DDS_RETCODE_ILLEGAL_OPERATION;
|
||||
}
|
||||
ddsrt_cond_broadcast (&ws->m_entity.m_cond);
|
||||
else
|
||||
{
|
||||
dds_waitset *ws = (dds_waitset *) wsent;
|
||||
|
||||
err_entity:
|
||||
if (e != &ws->m_entity)
|
||||
if ((ret = dds_entity_pin (entity, &e)) < 0)
|
||||
goto err_entity;
|
||||
|
||||
/* Entity must be "in scope": within the participant, domain or (self-evidently true) Cyclone DDS,
|
||||
depending on the parent of the waitset, so that one can't use a waitset created in participant
|
||||
A to wait for entities in participant B, &c. While there is no technical obstacle (though
|
||||
there might be one for cross-domain use one day), it seems rather unhygienic practice. */
|
||||
if (!dds_entity_in_scope (e, ws->m_entity.m_parent))
|
||||
{
|
||||
ret = DDS_RETCODE_BAD_PARAMETER;
|
||||
goto err_scope;
|
||||
}
|
||||
|
||||
/* This will fail if given entity is already attached (or deleted). */
|
||||
struct dds_waitset_attach_observer_arg attach_arg = { .x = x };
|
||||
ret = dds_entity_observer_register (e, ws, dds_waitset_observer, dds_waitset_attach_observer, &attach_arg, dds_waitset_delete_observer);
|
||||
|
||||
err_scope:
|
||||
dds_entity_unpin (e);
|
||||
err_waitset:
|
||||
dds_waitset_unlock (ws);
|
||||
return ret;
|
||||
err_entity:
|
||||
dds_entity_unpin (&ws->m_entity);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
dds_return_t dds_waitset_detach (dds_entity_t waitset, dds_entity_t entity)
|
||||
{
|
||||
dds_waitset *ws;
|
||||
dds_entity *e;
|
||||
dds_entity *wsent;
|
||||
dds_return_t ret;
|
||||
|
||||
if ((ret = dds_waitset_lock (waitset, &ws)) != DDS_RETCODE_OK)
|
||||
if ((ret = dds_entity_pin (waitset, &wsent)) != DDS_RETCODE_OK)
|
||||
return ret;
|
||||
|
||||
/* Possibly fails when entity was not attached. */
|
||||
if (waitset == entity)
|
||||
ret = dds_entity_observer_unregister (&ws->m_entity, &ws->m_entity);
|
||||
else if ((ret = dds_entity_pin (entity, &e)) < 0)
|
||||
; /* entity invalid */
|
||||
else
|
||||
else if (dds_entity_kind (wsent) != DDS_KIND_WAITSET)
|
||||
{
|
||||
ret = dds_entity_observer_unregister (e, &ws->m_entity);
|
||||
dds_entity_unpin (e);
|
||||
}
|
||||
|
||||
if (ret == DDS_RETCODE_OK)
|
||||
{
|
||||
dds_waitset_remove (ws, entity);
|
||||
dds_entity_unpin (wsent);
|
||||
return DDS_RETCODE_ILLEGAL_OPERATION;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ret != DDS_RETCODE_PRECONDITION_NOT_MET)
|
||||
dds_waitset *ws = (dds_waitset *) wsent;
|
||||
dds_entity *e;
|
||||
/* Possibly fails when entity was not attached. */
|
||||
if (waitset == entity)
|
||||
ret = dds_entity_observer_unregister (&ws->m_entity, ws, true);
|
||||
else if ((ret = dds_entity_pin (entity, &e)) < 0)
|
||||
; /* entity invalid */
|
||||
else
|
||||
{
|
||||
ret = dds_entity_observer_unregister (e, ws, true);
|
||||
dds_entity_unpin (e);
|
||||
}
|
||||
|
||||
dds_entity_unpin (&ws->m_entity);
|
||||
if (ret != DDS_RETCODE_OK && ret != DDS_RETCODE_PRECONDITION_NOT_MET)
|
||||
ret = DDS_RETCODE_BAD_PARAMETER;
|
||||
return ret;
|
||||
}
|
||||
dds_waitset_unlock (ws);
|
||||
return ret;
|
||||
}
|
||||
|
||||
dds_return_t dds_waitset_wait_until (dds_entity_t waitset, dds_attach_t *xs, size_t nxs, dds_time_t abstimeout)
|
||||
|
@ -299,7 +377,6 @@ dds_return_t dds_waitset_set_trigger (dds_entity_t waitset, bool trigger)
|
|||
{
|
||||
dds_entity *ent;
|
||||
dds_return_t rc;
|
||||
|
||||
if ((rc = dds_entity_pin (waitset, &ent)) != DDS_RETCODE_OK)
|
||||
return rc;
|
||||
else if (dds_entity_kind (ent) != DDS_KIND_WAITSET)
|
||||
|
@ -307,11 +384,10 @@ dds_return_t dds_waitset_set_trigger (dds_entity_t waitset, bool trigger)
|
|||
dds_entity_unpin (ent);
|
||||
return DDS_RETCODE_ILLEGAL_OPERATION;
|
||||
}
|
||||
|
||||
ddsrt_mutex_lock (&ent->m_observers_lock);
|
||||
dds_entity_trigger_set (ent, trigger);
|
||||
ddsrt_mutex_unlock (&ent->m_observers_lock);
|
||||
|
||||
dds_entity_unpin (ent);
|
||||
return DDS_RETCODE_OK;
|
||||
else
|
||||
{
|
||||
dds_entity_trigger_set (ent, trigger);
|
||||
dds_entity_unpin (ent);
|
||||
return DDS_RETCODE_OK;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -981,21 +981,14 @@ static uint32_t whc_default_remove_acked_messages_full (struct whc_impl *whc, se
|
|||
/* Delete it - but this may not result in deleting the index node as
|
||||
there must still be a more recent one available */
|
||||
#ifndef NDEBUG
|
||||
struct whc_node whcn_template;
|
||||
union {
|
||||
struct whc_idxnode idxn;
|
||||
char pad[sizeof (struct whc_idxnode) + sizeof (struct whc_node *)];
|
||||
} template;
|
||||
template.idxn.headidx = 0;
|
||||
template.idxn.hist[0] = &whcn_template;
|
||||
whcn_template.serdata = ddsi_serdata_ref (oldn->serdata);
|
||||
struct whc_idxnode template;
|
||||
template.iid = idxn->iid;
|
||||
assert (oldn->seq < whcn->seq);
|
||||
#endif
|
||||
TRACE (" del %p %"PRId64, (void *) oldn, oldn->seq);
|
||||
whc_delete_one (whc, oldn);
|
||||
#ifndef NDEBUG
|
||||
assert (ddsrt_hh_lookup (whc->idx_hash, &template) == idxn);
|
||||
ddsi_serdata_unref (whcn_template.serdata);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#include "dds/ddsi/ddsi_tkmap.h"
|
||||
#include "dds/ddsi/q_thread.h"
|
||||
#include "dds/ddsi/q_xmsg.h"
|
||||
#include "dds/ddsi/q_rhc.h"
|
||||
#include "dds/ddsi/ddsi_rhc.h"
|
||||
#include "dds/ddsi/ddsi_serdata.h"
|
||||
#include "dds__stream.h"
|
||||
#include "dds/ddsi/q_transmit.h"
|
||||
|
@ -71,9 +71,9 @@ dds_return_t dds_write_ts (dds_entity_t writer, const void *data, dds_time_t tim
|
|||
return ret;
|
||||
}
|
||||
|
||||
static dds_return_t try_store (struct rhc *rhc, const struct proxy_writer_info *pwr_info, struct ddsi_serdata *payload, struct ddsi_tkmap_instance *tk, dds_duration_t *max_block_ms)
|
||||
static dds_return_t try_store (struct ddsi_rhc *rhc, const struct ddsi_writer_info *pwr_info, struct ddsi_serdata *payload, struct ddsi_tkmap_instance *tk, dds_duration_t *max_block_ms)
|
||||
{
|
||||
while (! rhc_store (rhc, pwr_info, payload, tk))
|
||||
while (! ddsi_rhc_store (rhc, pwr_info, payload, tk))
|
||||
{
|
||||
if (*max_block_ms > 0)
|
||||
{
|
||||
|
@ -98,8 +98,8 @@ static dds_return_t deliver_locally (struct writer *wr, struct ddsi_serdata *pay
|
|||
if (rdary[0])
|
||||
{
|
||||
dds_duration_t max_block_ms = wr->xqos->reliability.max_blocking_time;
|
||||
struct proxy_writer_info pwr_info;
|
||||
make_proxy_writer_info (&pwr_info, &wr->e, wr->xqos);
|
||||
struct ddsi_writer_info pwr_info;
|
||||
ddsi_make_writer_info (&pwr_info, &wr->e, wr->xqos);
|
||||
for (uint32_t i = 0; rdary[i]; i++) {
|
||||
DDS_CTRACE (&wr->e.gv->logconfig, "reader "PGUIDFMT"\n", PGUID (rdary[i]->e.guid));
|
||||
if ((ret = try_store (rdary[i]->rhc, &pwr_info, payload, tk, &max_block_ms)) != DDS_RETCODE_OK)
|
||||
|
@ -120,11 +120,11 @@ static dds_return_t deliver_locally (struct writer *wr, struct ddsi_serdata *pay
|
|||
reliable samples that are rejected are simply discarded. */
|
||||
ddsrt_avl_iter_t it;
|
||||
struct pwr_rd_match *m;
|
||||
struct proxy_writer_info pwr_info;
|
||||
struct ddsi_writer_info wrinfo;
|
||||
const struct ephash *gh = wr->e.gv->guid_hash;
|
||||
dds_duration_t max_block_ms = wr->xqos->reliability.max_blocking_time;
|
||||
ddsrt_mutex_unlock (&wr->rdary.rdary_lock);
|
||||
make_proxy_writer_info (&pwr_info, &wr->e, wr->xqos);
|
||||
ddsi_make_writer_info (&wrinfo, &wr->e, wr->xqos);
|
||||
ddsrt_mutex_lock (&wr->e.lock);
|
||||
for (m = ddsrt_avl_iter_first (&wr_local_readers_treedef, &wr->local_readers, &it); m != NULL; m = ddsrt_avl_iter_next (&it))
|
||||
{
|
||||
|
@ -133,7 +133,7 @@ static dds_return_t deliver_locally (struct writer *wr, struct ddsi_serdata *pay
|
|||
{
|
||||
DDS_CTRACE (&wr->e.gv->logconfig, "reader-via-guid "PGUIDFMT"\n", PGUID (rd->e.guid));
|
||||
/* Copied the return value ignore from DDSI deliver_user_data () function. */
|
||||
if ((ret = try_store (rd->rhc, &pwr_info, payload, tk, &max_block_ms)) != DDS_RETCODE_OK)
|
||||
if ((ret = try_store (rd->rhc, &wrinfo, payload, tk, &max_block_ms)) != DDS_RETCODE_OK)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,34 +51,36 @@ static dds_return_t dds_writer_status_validate (uint32_t mask)
|
|||
|
||||
static void dds_writer_status_cb (void *ventity, const status_cb_data_t *data)
|
||||
{
|
||||
struct dds_entity * const entity = ventity;
|
||||
dds_writer * const wr = ventity;
|
||||
|
||||
/* When data is NULL, it means that the writer is deleted. */
|
||||
/* When data is NULL, it means that the DDSI reader is deleted. */
|
||||
if (data == NULL)
|
||||
{
|
||||
/* Release the initial claim that was done during the create. This
|
||||
* will indicate that further API deletion is now possible. */
|
||||
dds_handle_unpin (&entity->m_hdllink);
|
||||
ddsrt_mutex_lock (&wr->m_entity.m_mutex);
|
||||
wr->m_wr = NULL;
|
||||
ddsrt_cond_broadcast (&wr->m_entity.m_cond);
|
||||
ddsrt_mutex_unlock (&wr->m_entity.m_mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
struct dds_listener const * const lst = &entity->m_listener;
|
||||
struct dds_listener const * const lst = &wr->m_entity.m_listener;
|
||||
enum dds_status_id status_id = (enum dds_status_id) data->raw_status_id;
|
||||
bool invoke = false;
|
||||
void *vst = NULL;
|
||||
int32_t *reset[2] = { NULL, NULL };
|
||||
|
||||
ddsrt_mutex_lock (&entity->m_observers_lock);
|
||||
while (entity->m_cb_count > 0)
|
||||
ddsrt_cond_wait (&entity->m_observers_cond, &entity->m_observers_lock);
|
||||
entity->m_cb_count++;
|
||||
/* FIXME: why wait if no listener is set? */
|
||||
ddsrt_mutex_lock (&wr->m_entity.m_observers_lock);
|
||||
while (wr->m_entity.m_cb_count > 0)
|
||||
ddsrt_cond_wait (&wr->m_entity.m_observers_cond, &wr->m_entity.m_observers_lock);
|
||||
|
||||
/* Reset the status for possible Listener call.
|
||||
* When a listener is not called, the status will be set (again). */
|
||||
dds_entity_status_reset (entity, (status_mask_t) (1u << status_id));
|
||||
dds_entity_status_reset (&wr->m_entity, (status_mask_t) (1u << status_id));
|
||||
|
||||
/* Update status metrics. */
|
||||
dds_writer * const wr = (dds_writer *) entity;
|
||||
switch (status_id)
|
||||
{
|
||||
case DDS_OFFERED_DEADLINE_MISSED_STATUS_ID: {
|
||||
|
@ -136,23 +138,31 @@ static void dds_writer_status_cb (void *ventity, const status_cb_data_t *data)
|
|||
assert (0);
|
||||
}
|
||||
|
||||
if (invoke)
|
||||
const uint32_t enabled = (ddsrt_atomic_ld32 (&wr->m_entity.m_status.m_status_and_mask) & ((1u << status_id) << SAM_ENABLED_SHIFT));
|
||||
if (enabled == 0)
|
||||
{
|
||||
ddsrt_mutex_unlock (&entity->m_observers_lock);
|
||||
dds_entity_invoke_listener(entity, status_id, vst);
|
||||
ddsrt_mutex_lock (&entity->m_observers_lock);
|
||||
/* Don't invoke listeners or set status flag if masked */
|
||||
}
|
||||
else if (invoke)
|
||||
{
|
||||
wr->m_entity.m_cb_pending_count++;
|
||||
wr->m_entity.m_cb_count++;
|
||||
ddsrt_mutex_unlock (&wr->m_entity.m_observers_lock);
|
||||
dds_entity_invoke_listener (&wr->m_entity, status_id, vst);
|
||||
ddsrt_mutex_lock (&wr->m_entity.m_observers_lock);
|
||||
wr->m_entity.m_cb_count--;
|
||||
wr->m_entity.m_cb_pending_count--;
|
||||
*reset[0] = 0;
|
||||
if (reset[1])
|
||||
*reset[1] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
dds_entity_status_set (entity, (status_mask_t) (1u << status_id));
|
||||
dds_entity_status_set (&wr->m_entity, (status_mask_t) (1u << status_id));
|
||||
}
|
||||
|
||||
entity->m_cb_count--;
|
||||
ddsrt_cond_broadcast (&entity->m_observers_cond);
|
||||
ddsrt_mutex_unlock (&entity->m_observers_lock);
|
||||
ddsrt_cond_broadcast (&wr->m_entity.m_observers_cond);
|
||||
ddsrt_mutex_unlock (&wr->m_entity.m_observers_lock);
|
||||
}
|
||||
|
||||
static uint32_t get_bandwidth_limit (dds_transport_priority_qospolicy_t transport_priority)
|
||||
|
@ -166,18 +176,32 @@ static uint32_t get_bandwidth_limit (dds_transport_priority_qospolicy_t transpor
|
|||
#endif
|
||||
}
|
||||
|
||||
static dds_return_t dds_writer_close (dds_entity *e) ddsrt_nonnull_all;
|
||||
static void dds_writer_interrupt (dds_entity *e) ddsrt_nonnull_all;
|
||||
|
||||
static dds_return_t dds_writer_close (dds_entity *e)
|
||||
static void dds_writer_interrupt (dds_entity *e)
|
||||
{
|
||||
dds_writer * const wr = (dds_writer *) e;
|
||||
dds_return_t ret;
|
||||
thread_state_awake (lookup_thread_state (), &e->m_domain->gv);
|
||||
nn_xpack_send (wr->m_xp, false);
|
||||
if ((ret = delete_writer (&e->m_domain->gv, &e->m_guid)) < 0)
|
||||
ret = DDS_RETCODE_ERROR;
|
||||
struct q_globals * const gv = &e->m_domain->gv;
|
||||
thread_state_awake (lookup_thread_state (), gv);
|
||||
unblock_throttled_writer (gv, &e->m_guid);
|
||||
thread_state_asleep (lookup_thread_state ());
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void dds_writer_close (dds_entity *e) ddsrt_nonnull_all;
|
||||
|
||||
static void dds_writer_close (dds_entity *e)
|
||||
{
|
||||
struct dds_writer * const wr = (struct dds_writer *) e;
|
||||
struct q_globals * const gv = &e->m_domain->gv;
|
||||
struct thread_state1 * const ts1 = lookup_thread_state ();
|
||||
thread_state_awake (ts1, gv);
|
||||
nn_xpack_send (wr->m_xp, false);
|
||||
(void) delete_writer (gv, &e->m_guid);
|
||||
thread_state_asleep (ts1);
|
||||
|
||||
ddsrt_mutex_lock (&e->m_mutex);
|
||||
while (wr->m_wr != NULL)
|
||||
ddsrt_cond_wait (&e->m_cond, &e->m_mutex);
|
||||
ddsrt_mutex_unlock (&e->m_mutex);
|
||||
}
|
||||
|
||||
static dds_return_t dds_writer_delete (dds_entity *e) ddsrt_nonnull_all;
|
||||
|
@ -190,12 +214,7 @@ static dds_return_t dds_writer_delete (dds_entity *e)
|
|||
thread_state_awake (lookup_thread_state (), &e->m_domain->gv);
|
||||
nn_xpack_free (wr->m_xp);
|
||||
thread_state_asleep (lookup_thread_state ());
|
||||
if ((ret = dds_delete (wr->m_topic->m_entity.m_hdllink.hdl)) == DDS_RETCODE_OK)
|
||||
{
|
||||
ret = dds_delete_impl (e->m_parent->m_hdllink.hdl, true);
|
||||
if (ret == DDS_RETCODE_BAD_PARAMETER)
|
||||
ret = DDS_RETCODE_OK;
|
||||
}
|
||||
ret = dds_delete (wr->m_topic->m_entity.m_hdllink.hdl);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -238,6 +257,7 @@ static struct whc *make_whc (struct dds_domain *dom, const dds_qos_t *qos)
|
|||
}
|
||||
|
||||
const struct dds_entity_deriver dds_entity_deriver_writer = {
|
||||
.interrupt = dds_writer_interrupt,
|
||||
.close = dds_writer_close,
|
||||
.delete = dds_writer_delete,
|
||||
.set_qos = dds_writer_qos_set,
|
||||
|
@ -251,6 +271,7 @@ dds_entity_t dds_create_writer (dds_entity_t participant_or_publisher, dds_entit
|
|||
dds_writer *wr;
|
||||
dds_entity_t writer;
|
||||
dds_publisher *pub = NULL;
|
||||
dds_participant *pp;
|
||||
dds_topic *tp;
|
||||
dds_entity_t publisher;
|
||||
|
||||
|
@ -259,7 +280,7 @@ dds_entity_t dds_create_writer (dds_entity_t participant_or_publisher, dds_entit
|
|||
if ((rc = dds_entity_pin (participant_or_publisher, &p_or_p)) != DDS_RETCODE_OK)
|
||||
return rc;
|
||||
if (dds_entity_kind (p_or_p) == DDS_KIND_PARTICIPANT)
|
||||
publisher = dds_create_publisher(participant_or_publisher, qos, NULL);
|
||||
publisher = dds_create_publisher (participant_or_publisher, qos, NULL);
|
||||
else
|
||||
publisher = participant_or_publisher;
|
||||
dds_entity_unpin (p_or_p);
|
||||
|
@ -274,9 +295,14 @@ dds_entity_t dds_create_writer (dds_entity_t participant_or_publisher, dds_entit
|
|||
|
||||
if ((rc = dds_topic_lock (topic, &tp)) != DDS_RETCODE_OK)
|
||||
goto err_tp_lock;
|
||||
|
||||
assert (tp->m_stopic);
|
||||
assert (pub->m_entity.m_domain == tp->m_entity.m_domain);
|
||||
|
||||
pp = dds_entity_participant (&pub->m_entity);
|
||||
if (pp != dds_entity_participant (&tp->m_entity))
|
||||
{
|
||||
rc = DDS_RETCODE_BAD_PARAMETER;
|
||||
goto err_pp_mismatch;
|
||||
}
|
||||
|
||||
/* Merge Topic & Publisher qos */
|
||||
wqos = dds_create_qos ();
|
||||
|
@ -304,34 +330,26 @@ dds_entity_t dds_create_writer (dds_entity_t participant_or_publisher, dds_entit
|
|||
wr->m_whc = make_whc (pub->m_entity.m_domain, wqos);
|
||||
wr->whc_batch = pub->m_entity.m_domain->gv.config.whc_batch;
|
||||
|
||||
/* Extra claim of this writer to make sure that the delete waits until DDSI
|
||||
* has deleted its writer as well. This can be known through the callback. */
|
||||
dds_handle_repin (&wr->m_entity.m_hdllink);
|
||||
|
||||
ddsrt_mutex_unlock (&tp->m_entity.m_mutex);
|
||||
ddsrt_mutex_unlock (&pub->m_entity.m_mutex);
|
||||
|
||||
thread_state_awake (lookup_thread_state (), &pub->m_entity.m_domain->gv);
|
||||
rc = new_writer (&wr->m_wr, &wr->m_entity.m_domain->gv, &wr->m_entity.m_guid, NULL, &pub->m_entity.m_participant->m_guid, tp->m_stopic, wqos, wr->m_whc, dds_writer_status_cb, wr);
|
||||
ddsrt_mutex_lock (&pub->m_entity.m_mutex);
|
||||
ddsrt_mutex_lock (&tp->m_entity.m_mutex);
|
||||
rc = new_writer (&wr->m_wr, &wr->m_entity.m_domain->gv, &wr->m_entity.m_guid, NULL, &pp->m_entity.m_guid, tp->m_stopic, wqos, wr->m_whc, dds_writer_status_cb, wr);
|
||||
assert(rc == DDS_RETCODE_OK);
|
||||
thread_state_asleep (lookup_thread_state ());
|
||||
|
||||
wr->m_entity.m_iid = get_entity_instance_id (&wr->m_entity.m_domain->gv, &wr->m_entity.m_guid);
|
||||
dds_entity_register_child (&pub->m_entity, &wr->m_entity);
|
||||
|
||||
dds_entity_init_complete (&wr->m_entity);
|
||||
dds_topic_unlock (tp);
|
||||
dds_publisher_unlock (pub);
|
||||
return writer;
|
||||
|
||||
err_bad_qos:
|
||||
err_pp_mismatch:
|
||||
dds_topic_unlock (tp);
|
||||
err_tp_lock:
|
||||
dds_publisher_unlock (pub);
|
||||
if ((pub->m_entity.m_flags & DDS_ENTITY_IMPLICIT) != 0){
|
||||
(void )dds_delete (publisher);
|
||||
}
|
||||
if ((pub->m_entity.m_flags & DDS_ENTITY_IMPLICIT) != 0)
|
||||
(void) dds_delete (publisher);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ set(ddsc_test_sources
|
|||
"builtin_topics.c"
|
||||
"config.c"
|
||||
"dispose.c"
|
||||
"domain.c"
|
||||
"entity_api.c"
|
||||
"entity_hierarchy.c"
|
||||
"entity_status.c"
|
||||
|
@ -30,6 +31,7 @@ set(ddsc_test_sources
|
|||
"publisher.c"
|
||||
"qos.c"
|
||||
"querycondition.c"
|
||||
"guardcondition.c"
|
||||
"readcondition.c"
|
||||
"reader.c"
|
||||
"reader_iterator.c"
|
||||
|
@ -45,6 +47,7 @@ set(ddsc_test_sources
|
|||
"unregister.c"
|
||||
"unsupported.c"
|
||||
"waitset.c"
|
||||
"waitset_torture.c"
|
||||
"write.c"
|
||||
"writer.c")
|
||||
|
||||
|
|
|
@ -308,3 +308,35 @@ CU_Test(ddsc_builtin_topics, builtin_qos, .init = setup, .fini = teardown)
|
|||
CU_ASSERT_FATAL(dds_sub_subscriber > 0);
|
||||
check_default_qos_of_builtin_entity(dds_sub_subscriber, 0);
|
||||
}
|
||||
|
||||
CU_Test(ddsc_builtin_topics, read_nothing)
|
||||
{
|
||||
dds_entity_t pp;
|
||||
dds_entity_t rd;
|
||||
dds_return_t ret;
|
||||
dds_sample_info_t si;
|
||||
void *raw1, *raw2;
|
||||
int32_t n1, n2;
|
||||
|
||||
pp = dds_create_participant (DDS_DOMAIN_DEFAULT, NULL, NULL);
|
||||
CU_ASSERT_FATAL (pp > 0);
|
||||
rd = dds_create_reader (pp, DDS_BUILTIN_TOPIC_DCPSSUBSCRIPTION, NULL, NULL);
|
||||
CU_ASSERT_FATAL (rd > 0);
|
||||
|
||||
/* Can't guarantee there's no other process around with a publication, but
|
||||
we can take until nothing remains. The point is checking handling of
|
||||
freeing memory when a loan was outstanding, memory had to be allocated,
|
||||
and subsequently had to be freed because of an absence of data. */
|
||||
raw1 = raw2 = NULL;
|
||||
n1 = dds_take (rd, &raw1, &si, 1, 1);
|
||||
CU_ASSERT_FATAL (n1 >= 0);
|
||||
n2 = dds_take (rd, &raw2, &si, 1, 1);
|
||||
CU_ASSERT_FATAL (n2 >= 0);
|
||||
ret = dds_return_loan (rd, &raw1, n1);
|
||||
CU_ASSERT_FATAL (ret == 0);
|
||||
ret = dds_return_loan (rd, &raw2, n2);
|
||||
CU_ASSERT_FATAL (ret == 0);
|
||||
|
||||
ret = dds_delete (pp);
|
||||
CU_ASSERT_FATAL (ret == 0);
|
||||
}
|
||||
|
|
|
@ -75,3 +75,46 @@ CU_Test(ddsc_config, simple_udp, .init = ddsrt_init, .fini = ddsrt_fini) {
|
|||
|
||||
dds_delete(participant);
|
||||
}
|
||||
|
||||
CU_Test(ddsc_config, user_config, .init = ddsrt_init, .fini = ddsrt_fini) {
|
||||
|
||||
CU_ASSERT_FATAL(dds_create_domain(1,
|
||||
"<"DDS_PROJECT_NAME"><Domain><Id>any</Id></Domain>"
|
||||
"<DDSI2E><Internal><MaxParticipants>2</MaxParticipants></Internal></DDSI2E>"
|
||||
"</"DDS_PROJECT_NAME">") == DDS_RETCODE_OK);
|
||||
|
||||
dds_entity_t participant_1;
|
||||
dds_entity_t participant_2;
|
||||
dds_entity_t participant_3;
|
||||
|
||||
participant_1 = dds_create_participant(1, NULL, NULL);
|
||||
|
||||
CU_ASSERT_FATAL(participant_1 > 0);
|
||||
|
||||
participant_2 = dds_create_participant(1, NULL, NULL);
|
||||
|
||||
CU_ASSERT_FATAL(participant_2 > 0);
|
||||
|
||||
participant_3 = dds_create_participant(1, NULL, NULL);
|
||||
|
||||
CU_ASSERT(participant_3 <= 0);
|
||||
|
||||
dds_delete(participant_3);
|
||||
dds_delete(participant_2);
|
||||
dds_delete(participant_1);
|
||||
}
|
||||
|
||||
CU_Test(ddsc_config, incorrect_config, .init = ddsrt_init, .fini = ddsrt_fini) {
|
||||
|
||||
CU_ASSERT_FATAL(dds_create_domain(1, NULL) == DDS_RETCODE_BAD_PARAMETER);
|
||||
CU_ASSERT_FATAL(dds_create_domain(1, "<CycloneDDS incorrect XML") != DDS_RETCODE_OK);
|
||||
CU_ASSERT_FATAL(dds_create_domain(DDS_DOMAIN_DEFAULT,
|
||||
"<"DDS_PROJECT_NAME"><Domain><Id>any</Id></Domain>"
|
||||
"<DDSI2E><Internal><MaxParticipants>2</MaxParticipants></Internal></DDSI2E>"
|
||||
"</"DDS_PROJECT_NAME">") == DDS_RETCODE_BAD_PARAMETER);
|
||||
CU_ASSERT_FATAL(dds_create_domain(2,
|
||||
"<"DDS_PROJECT_NAME"><Domain><Id>any</Id></Domain>"
|
||||
"<DDSI2E><Internal><MaxParticipants>2</MaxParticipants></Internal></DDSI2E>"
|
||||
"</"DDS_PROJECT_NAME">") == DDS_RETCODE_OK);
|
||||
CU_ASSERT_FATAL(dds_create_domain(2, "") == DDS_RETCODE_PRECONDITION_NOT_MET);
|
||||
}
|
||||
|
|
142
src/core/ddsc/tests/domain.c
Normal file
142
src/core/ddsc/tests/domain.c
Normal file
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
* Copyright(c) 2019 ADLINK Technology Limited and others
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
|
||||
* v. 1.0 which is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "dds/dds.h"
|
||||
#include "CUnit/Test.h"
|
||||
#include "config_env.h"
|
||||
#include "dds/version.h"
|
||||
#include "dds/ddsrt/environ.h"
|
||||
|
||||
CU_Test(ddsc_domain, get_domainid)
|
||||
{
|
||||
dds_entity_t pp, d, x;
|
||||
dds_return_t rc;
|
||||
uint32_t did;
|
||||
pp = dds_create_participant (0, NULL, NULL);
|
||||
CU_ASSERT_FATAL (pp > 0);
|
||||
d = dds_get_parent (pp);
|
||||
CU_ASSERT_FATAL (d > 0);
|
||||
x = dds_get_parent (d);
|
||||
CU_ASSERT_FATAL (x == DDS_CYCLONEDDS_HANDLE);
|
||||
x = dds_get_parent (x);
|
||||
CU_ASSERT_FATAL (x == 0);
|
||||
|
||||
rc = dds_get_domainid (pp, &did);
|
||||
CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
|
||||
CU_ASSERT_FATAL (did == 0);
|
||||
rc = dds_get_domainid (d, &did);
|
||||
CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
|
||||
CU_ASSERT_FATAL (did == 0);
|
||||
rc = dds_get_domainid (DDS_CYCLONEDDS_HANDLE, &did);
|
||||
CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
|
||||
CU_ASSERT_FATAL (did == DDS_DOMAIN_DEFAULT);
|
||||
rc = dds_delete (pp);
|
||||
CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
|
||||
}
|
||||
|
||||
CU_Test(ddsc_domain, delete_domain0)
|
||||
{
|
||||
dds_entity_t pp[3], d[3];
|
||||
dds_return_t rc;
|
||||
uint32_t did;
|
||||
for (dds_domainid_t i = 0; i < (dds_domainid_t) (sizeof (pp) / sizeof (pp[0])); i++)
|
||||
{
|
||||
pp[i] = dds_create_participant (0, NULL, NULL);
|
||||
CU_ASSERT_FATAL (pp[i] > 0);
|
||||
d[i] = dds_get_parent (pp[i]);
|
||||
CU_ASSERT_FATAL (d[i] > 0);
|
||||
if (i > 0)
|
||||
CU_ASSERT_FATAL (d[i] == d[i-1]);
|
||||
}
|
||||
rc = dds_delete (pp[0]);
|
||||
CU_ASSERT_FATAL (rc == 0);
|
||||
rc = dds_get_domainid (pp[0], &did);
|
||||
CU_ASSERT_FATAL (rc == DDS_RETCODE_BAD_PARAMETER);
|
||||
for (size_t i = 1; i < sizeof (pp) / sizeof (pp[0]); i++)
|
||||
{
|
||||
rc = dds_get_domainid (pp[i], &did);
|
||||
CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
|
||||
CU_ASSERT_FATAL (did == 0);
|
||||
}
|
||||
rc = dds_delete (d[1]);
|
||||
CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
|
||||
/* Deleting the domain should delete all participants in it as well,
|
||||
and as there is only a single domain in this test, that should
|
||||
de-initialize the library.
|
||||
|
||||
A non-initialized library returns PRECONDITION_NOT_MET; an
|
||||
initialized one given an invalid handle returns BAD_PARAMETER,
|
||||
so we can distinguish the two cases. */
|
||||
rc = dds_get_domainid (pp[1], &did);
|
||||
CU_ASSERT_FATAL (rc == DDS_RETCODE_PRECONDITION_NOT_MET);
|
||||
}
|
||||
|
||||
CU_Test(ddsc_domain, delete_domainM)
|
||||
{
|
||||
dds_entity_t pp[3], d[3], x;
|
||||
dds_return_t rc;
|
||||
uint32_t did;
|
||||
for (dds_domainid_t i = 0; i < (dds_domainid_t) (sizeof (pp) / sizeof (pp[0])); i++)
|
||||
{
|
||||
pp[i] = dds_create_participant (i, NULL, NULL);
|
||||
CU_ASSERT_FATAL (pp[i] > 0);
|
||||
d[i] = dds_get_parent (pp[i]);
|
||||
CU_ASSERT_FATAL (d[i] > 0);
|
||||
for (dds_domainid_t j = 0; j < i; j++)
|
||||
CU_ASSERT_FATAL (d[i] != d[j]);
|
||||
}
|
||||
|
||||
/* deleting participant 0 should tear down domain 0, but nothing else */
|
||||
rc = dds_delete (pp[0]);
|
||||
CU_ASSERT_FATAL (rc == 0);
|
||||
rc = dds_get_domainid (pp[0], &did);
|
||||
CU_ASSERT_FATAL (rc == DDS_RETCODE_BAD_PARAMETER);
|
||||
rc = dds_get_domainid (d[0], &did);
|
||||
CU_ASSERT_FATAL (rc == DDS_RETCODE_BAD_PARAMETER);
|
||||
|
||||
/* deleting domain should delete participant 1, but leave domain 2 alone */
|
||||
rc = dds_delete (d[1]);
|
||||
CU_ASSERT_FATAL (rc == 0);
|
||||
rc = dds_get_domainid (pp[1], &did);
|
||||
CU_ASSERT_FATAL (rc == DDS_RETCODE_BAD_PARAMETER);
|
||||
x = dds_get_parent (pp[2]);
|
||||
CU_ASSERT_FATAL (x == d[2]);
|
||||
|
||||
/* after deleting participant 2, everything should be gone */
|
||||
rc = dds_delete (pp[2]);
|
||||
CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
|
||||
rc = dds_get_domainid (pp[1], &did);
|
||||
CU_ASSERT_FATAL (rc == DDS_RETCODE_PRECONDITION_NOT_MET);
|
||||
}
|
||||
|
||||
CU_Test(ddsc_domain, delete_cyclonedds)
|
||||
{
|
||||
dds_entity_t pp[3], d[3];
|
||||
dds_return_t rc;
|
||||
uint32_t did;
|
||||
for (dds_domainid_t i = 0; i < (dds_domainid_t) (sizeof (pp) / sizeof (pp[0])); i++)
|
||||
{
|
||||
pp[i] = dds_create_participant (i, NULL, NULL);
|
||||
CU_ASSERT_FATAL (pp[i] > 0);
|
||||
d[i] = dds_get_parent (pp[i]);
|
||||
CU_ASSERT_FATAL (d[i] > 0);
|
||||
for (dds_domainid_t j = 0; j < i; j++)
|
||||
CU_ASSERT_FATAL (d[i] != d[j]);
|
||||
}
|
||||
|
||||
/* deleting participant 0 should tear down domain 0, but nothing else */
|
||||
rc = dds_delete (DDS_CYCLONEDDS_HANDLE);
|
||||
CU_ASSERT_FATAL (rc == 0);
|
||||
rc = dds_get_domainid (pp[0], &did);
|
||||
CU_ASSERT_FATAL (rc == DDS_RETCODE_PRECONDITION_NOT_MET);
|
||||
}
|
|
@ -290,9 +290,12 @@ CU_Test(ddsc_entity, get_entities, .init = create_entity, .fini = delete_entity)
|
|||
par = dds_get_parent (0);
|
||||
CU_ASSERT_EQUAL_FATAL(par, DDS_RETCODE_BAD_PARAMETER);
|
||||
|
||||
/* Get Parent, a participant doesn't have a parent. */
|
||||
/* Get Parent, a participant always has a parent (the domain). */
|
||||
par = dds_get_parent (entity);
|
||||
CU_ASSERT_EQUAL_FATAL(par, DDS_ENTITY_NIL);
|
||||
CU_ASSERT_NOT_EQUAL_FATAL(par, DDS_HANDLE_NIL);
|
||||
/* The domain has a parent: the pseudo-entity for the library */
|
||||
par = dds_get_parent (par);
|
||||
CU_ASSERT_EQUAL_FATAL(par, DDS_CYCLONEDDS_HANDLE);
|
||||
|
||||
/* ---------- Get Participant ------------ */
|
||||
|
||||
|
|
|
@ -313,7 +313,11 @@ CU_Test(ddsc_entity_get_parent, participant, .init=hierarchy_init, .fini=hierarc
|
|||
{
|
||||
dds_entity_t parent;
|
||||
parent = dds_get_parent(g_participant);
|
||||
CU_ASSERT_EQUAL_FATAL(parent, DDS_ENTITY_NIL);
|
||||
CU_ASSERT_NOT_EQUAL_FATAL(parent, DDS_ENTITY_NIL);
|
||||
parent = dds_get_parent(parent);
|
||||
CU_ASSERT_NOT_EQUAL_FATAL(parent, DDS_ENTITY_NIL);
|
||||
parent = dds_get_parent(parent);
|
||||
CU_ASSERT_NOT_EQUAL_FATAL(parent, DDS_CYCLONEDDS_HANDLE);
|
||||
}
|
||||
/*************************************************************************************************/
|
||||
|
||||
|
@ -362,13 +366,15 @@ CU_Test(ddsc_entity_get_children, null, .init=hierarchy_init, .fini=hierarchy_fi
|
|||
/*************************************************************************************************/
|
||||
|
||||
/*************************************************************************************************/
|
||||
#if SIZE_MAX > INT32_MAX
|
||||
CU_Test(ddsc_entity_get_children, invalid_size, .init=hierarchy_init, .fini=hierarchy_fini)
|
||||
{
|
||||
dds_return_t ret;
|
||||
dds_entity_t child;
|
||||
ret = dds_get_children(g_participant, &child, INT32_MAX);
|
||||
ret = dds_get_children(g_participant, &child, SIZE_MAX);
|
||||
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER);
|
||||
}
|
||||
#endif
|
||||
/*************************************************************************************************/
|
||||
|
||||
/*************************************************************************************************/
|
||||
|
@ -866,9 +872,8 @@ CU_Test(ddsc_entity_get_children, implicit_publisher)
|
|||
dds_delete(writer);
|
||||
|
||||
ret = dds_get_children(participant, child2, 2);
|
||||
CU_ASSERT_EQUAL_FATAL(ret, 2);
|
||||
CU_ASSERT_EQUAL_FATAL(ret, 1);
|
||||
CU_ASSERT_FATAL( (child2[0] == child[0]) || (child2[0] == child[1]) );
|
||||
CU_ASSERT_FATAL( (child2[1] == child[0]) || (child2[1] == child[1]) );
|
||||
|
||||
dds_delete(topic);
|
||||
dds_delete(participant);
|
||||
|
@ -911,9 +916,8 @@ CU_Test(ddsc_entity_get_children, implicit_subscriber)
|
|||
dds_delete(reader);
|
||||
|
||||
ret = dds_get_children(participant, child2, 2);
|
||||
CU_ASSERT_EQUAL_FATAL(ret, 2);
|
||||
CU_ASSERT_EQUAL_FATAL(ret, 1);
|
||||
CU_ASSERT_FATAL( (child2[0] == child[0]) || (child2[0] == child[1]) );
|
||||
CU_ASSERT_FATAL( (child2[1] == child[0]) || (child2[1] == child[1]) );
|
||||
|
||||
dds_delete(topic);
|
||||
dds_delete(participant);
|
||||
|
@ -947,7 +951,7 @@ CU_Test(ddsc_entity_get_parent, implicit_publisher)
|
|||
dds_delete(writer);
|
||||
|
||||
ret = dds_delete(parent);
|
||||
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
|
||||
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER);
|
||||
dds_delete(participant);
|
||||
}
|
||||
/*************************************************************************************************/
|
||||
|
@ -978,7 +982,7 @@ CU_Test(ddsc_entity_get_parent, implicit_subscriber)
|
|||
dds_delete(reader);
|
||||
|
||||
ret = dds_delete(parent);
|
||||
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
|
||||
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER);
|
||||
dds_delete(participant);
|
||||
|
||||
}
|
||||
|
|
187
src/core/ddsc/tests/guardcondition.c
Normal file
187
src/core/ddsc/tests/guardcondition.c
Normal file
|
@ -0,0 +1,187 @@
|
|||
/*
|
||||
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
|
||||
* v. 1.0 which is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "dds/dds.h"
|
||||
#include "CUnit/Theory.h"
|
||||
#include "RoundTrip.h"
|
||||
|
||||
#include "dds/ddsrt/cdtors.h"
|
||||
#include "dds/ddsrt/misc.h"
|
||||
#include "dds/ddsrt/process.h"
|
||||
#include "dds/ddsrt/threads.h"
|
||||
#include "dds/ddsrt/atomics.h"
|
||||
#include "dds/ddsrt/time.h"
|
||||
|
||||
CU_Test (ddsc_guardcond_create, cyclonedds)
|
||||
{
|
||||
dds_entity_t gc;
|
||||
dds_return_t rc;
|
||||
/* Expect an uninitialised library */
|
||||
rc = dds_get_parent (DDS_CYCLONEDDS_HANDLE);
|
||||
CU_ASSERT_FATAL (rc == DDS_RETCODE_PRECONDITION_NOT_MET);
|
||||
gc = dds_create_guardcondition (DDS_CYCLONEDDS_HANDLE);
|
||||
CU_ASSERT_FATAL (gc > 0);
|
||||
rc = dds_delete (DDS_CYCLONEDDS_HANDLE);
|
||||
CU_ASSERT_FATAL (rc == 0);
|
||||
/* And the same afterward */
|
||||
rc = dds_get_parent (DDS_CYCLONEDDS_HANDLE);
|
||||
CU_ASSERT_FATAL (rc == DDS_RETCODE_PRECONDITION_NOT_MET);
|
||||
}
|
||||
|
||||
CU_Test (ddsc_guardcond_create, domain)
|
||||
{
|
||||
dds_entity_t par, dom, gc;
|
||||
dds_return_t rc;
|
||||
par = dds_create_participant (0, NULL, NULL);
|
||||
CU_ASSERT_FATAL (par > 0);
|
||||
dom = dds_get_parent (par);
|
||||
CU_ASSERT_FATAL (dom > 0);
|
||||
gc = dds_create_guardcondition (dom);
|
||||
CU_ASSERT_FATAL (gc > 0);
|
||||
rc = dds_delete (dom);
|
||||
CU_ASSERT_FATAL (rc == 0);
|
||||
}
|
||||
|
||||
CU_Test (ddsc_guardcond_create, participant)
|
||||
{
|
||||
dds_entity_t par, gc;
|
||||
dds_return_t rc;
|
||||
par = dds_create_participant (0, NULL, NULL);
|
||||
CU_ASSERT_FATAL (par > 0);
|
||||
gc = dds_create_guardcondition (par);
|
||||
CU_ASSERT_FATAL (gc > 0);
|
||||
rc = dds_delete (par);
|
||||
CU_ASSERT_FATAL (rc == 0);
|
||||
}
|
||||
|
||||
CU_Test (ddsc_guardcond, set_trigger)
|
||||
{
|
||||
dds_entity_t par, gc;
|
||||
dds_return_t rc;
|
||||
bool trig;
|
||||
par = dds_create_participant (0, NULL, NULL);
|
||||
CU_ASSERT_FATAL (par > 0);
|
||||
gc = dds_create_guardcondition (par);
|
||||
CU_ASSERT_FATAL (gc > 0);
|
||||
rc = dds_read_guardcondition (gc, &trig);
|
||||
CU_ASSERT_FATAL (rc == 0);
|
||||
CU_ASSERT (!trig);
|
||||
rc = dds_set_guardcondition (gc, true);
|
||||
CU_ASSERT_FATAL (rc == 0);
|
||||
rc = dds_read_guardcondition (gc, &trig);
|
||||
CU_ASSERT_FATAL (rc == 0);
|
||||
CU_ASSERT (trig);
|
||||
rc = dds_delete (par);
|
||||
CU_ASSERT_FATAL (rc == 0);
|
||||
}
|
||||
|
||||
CU_Test (ddsc_guardcond, take_trigger)
|
||||
{
|
||||
dds_entity_t par, gc;
|
||||
dds_return_t rc;
|
||||
bool trig;
|
||||
par = dds_create_participant (0, NULL, NULL);
|
||||
CU_ASSERT_FATAL (par > 0);
|
||||
gc = dds_create_guardcondition (par);
|
||||
CU_ASSERT_FATAL (gc > 0);
|
||||
rc = dds_read_guardcondition (gc, &trig);
|
||||
CU_ASSERT_FATAL (rc == 0);
|
||||
CU_ASSERT (!trig);
|
||||
rc = dds_set_guardcondition (gc, true);
|
||||
CU_ASSERT_FATAL (rc == 0);
|
||||
rc = dds_take_guardcondition (gc, &trig);
|
||||
CU_ASSERT_FATAL (rc == 0);
|
||||
CU_ASSERT (trig);
|
||||
rc = dds_read_guardcondition (gc, &trig);
|
||||
CU_ASSERT_FATAL (rc == 0);
|
||||
CU_ASSERT (!trig);
|
||||
rc = dds_delete (par);
|
||||
CU_ASSERT_FATAL (rc == 0);
|
||||
}
|
||||
|
||||
CU_Test (ddsc_guardcond, waitset)
|
||||
{
|
||||
dds_entity_t par, gc, ws;
|
||||
dds_attach_t xs[1];
|
||||
dds_return_t rc;
|
||||
par = dds_create_participant (0, NULL, NULL);
|
||||
CU_ASSERT_FATAL (par > 0);
|
||||
gc = dds_create_guardcondition (par);
|
||||
CU_ASSERT_FATAL (gc > 0);
|
||||
ws = dds_create_waitset (par);
|
||||
CU_ASSERT_FATAL (ws > 0);
|
||||
rc = dds_waitset_attach (ws, gc, gc);
|
||||
CU_ASSERT_FATAL (rc == 0);
|
||||
/* guard cond not triggered: waitset should return 0 */
|
||||
rc = dds_waitset_wait (ws, xs, 1, 0);
|
||||
CU_ASSERT (rc == 0);
|
||||
rc = dds_set_guardcondition (gc, true);
|
||||
CU_ASSERT_FATAL (rc == 0);
|
||||
/* guard triggered: waitset should return it */
|
||||
rc = dds_waitset_wait (ws, xs, 1, 0);
|
||||
CU_ASSERT (rc == 1);
|
||||
CU_ASSERT (xs[0] == gc);
|
||||
rc = dds_delete (par);
|
||||
CU_ASSERT_FATAL (rc == 0);
|
||||
}
|
||||
|
||||
struct guardcond_thread_arg {
|
||||
dds_entity_t gc;
|
||||
dds_return_t ret;
|
||||
};
|
||||
|
||||
static uint32_t guardcond_thread (void *varg)
|
||||
{
|
||||
struct guardcond_thread_arg *arg = varg;
|
||||
/* 200ms sleep is hopefully always long enough for the main thread to
|
||||
enter wait() and block; a further 1800ms (see wait call) similarly
|
||||
for the guard condition to actually trigger it. */
|
||||
dds_sleepfor (DDS_MSECS (200));
|
||||
arg->ret = dds_set_guardcondition (arg->gc, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
CU_Test (ddsc_guardcond, waitset_thread)
|
||||
{
|
||||
dds_entity_t par, gc, ws;
|
||||
dds_attach_t xs[1];
|
||||
dds_return_t rc;
|
||||
ddsrt_thread_t tid;
|
||||
ddsrt_threadattr_t tattr;
|
||||
|
||||
par = dds_create_participant (0, NULL, NULL);
|
||||
CU_ASSERT_FATAL (par > 0);
|
||||
gc = dds_create_guardcondition (par);
|
||||
CU_ASSERT_FATAL (gc > 0);
|
||||
ws = dds_create_waitset (par);
|
||||
CU_ASSERT_FATAL (ws > 0);
|
||||
rc = dds_waitset_attach (ws, gc, gc);
|
||||
CU_ASSERT_FATAL (rc == 0);
|
||||
|
||||
struct guardcond_thread_arg arg = { .gc = gc };
|
||||
ddsrt_threadattr_init (&tattr);
|
||||
rc = ddsrt_thread_create (&tid, "guardcond_thread", &tattr, guardcond_thread, &arg);
|
||||
CU_ASSERT_FATAL (rc == 0);
|
||||
|
||||
rc = dds_waitset_wait (ws, xs, 1, DDS_SECS (2));
|
||||
CU_ASSERT (rc == 1);
|
||||
CU_ASSERT (xs[0] == gc);
|
||||
|
||||
rc = ddsrt_thread_join (tid, NULL);
|
||||
CU_ASSERT_FATAL (rc == 0);
|
||||
CU_ASSERT_FATAL (arg.ret == 0);
|
||||
|
||||
rc = dds_delete (par);
|
||||
CU_ASSERT_FATAL (rc == 0);
|
||||
}
|
|
@ -132,6 +132,7 @@ CU_Test(ddsc_instance_get_key, registered_instance, .init=setup, .fini=teardown)
|
|||
ret = dds_instance_get_key(writer, handle, &key_data);
|
||||
|
||||
CU_ASSERT_PTR_NOT_NULL_FATAL(key_data.ip);
|
||||
assert (key_data.ip != NULL); /* for the benefit of clang's static analyzer */
|
||||
CU_ASSERT_STRING_EQUAL_FATAL(key_data.ip, data.ip);
|
||||
CU_ASSERT_EQUAL_FATAL(key_data.port, data.port);
|
||||
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
|
||||
|
@ -162,6 +163,7 @@ CU_Test(ddsc_instance_get_key, readcondition, .init=setup, .fini=teardown)
|
|||
ret = dds_instance_get_key(readcondition, handle, &key_data);
|
||||
|
||||
CU_ASSERT_PTR_NOT_NULL_FATAL(key_data.ip);
|
||||
assert (key_data.ip != NULL); /* for the benefit of clang's static analyzer */
|
||||
CU_ASSERT_STRING_EQUAL_FATAL(key_data.ip, data.ip);
|
||||
CU_ASSERT_EQUAL_FATAL(key_data.port, data.port);
|
||||
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
|
||||
|
@ -192,6 +194,7 @@ CU_Test(ddsc_instance_get_key, querycondition, .init=setup, .fini=teardown)
|
|||
ret = dds_instance_get_key(querycondition, handle, &key_data);
|
||||
|
||||
CU_ASSERT_PTR_NOT_NULL_FATAL(key_data.ip);
|
||||
assert (key_data.ip != NULL); /* for the benefit of clang's static analyzer */
|
||||
CU_ASSERT_STRING_EQUAL_FATAL(key_data.ip, data.ip);
|
||||
CU_ASSERT_EQUAL_FATAL(key_data.port, data.port);
|
||||
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
|
||||
|
|
|
@ -727,7 +727,9 @@ CU_Test(ddsc_listener, publication_matched, .init=init_triggering_test, .fini=fi
|
|||
CU_ASSERT_EQUAL_FATAL(publication_matched.last_subscription_handle, reader_hdl);
|
||||
|
||||
/* Reset the trigger flags. */
|
||||
ddsrt_mutex_lock(&g_mutex);
|
||||
cb_called = 0;
|
||||
ddsrt_mutex_unlock(&g_mutex);
|
||||
|
||||
/* Un-match the publication by deleting the reader. */
|
||||
dds_delete(g_reader);
|
||||
|
@ -789,7 +791,9 @@ CU_Test(ddsc_listener, subscription_matched, .init=init_triggering_test, .fini=f
|
|||
CU_ASSERT_EQUAL_FATAL(subscription_matched.last_publication_handle, writer_hdl);
|
||||
|
||||
/* Reset the trigger flags. */
|
||||
ddsrt_mutex_lock(&g_mutex);
|
||||
cb_called = 0;
|
||||
ddsrt_mutex_unlock(&g_mutex);
|
||||
|
||||
/* Un-match the subscription by deleting the writer. */
|
||||
dds_delete(g_writer);
|
||||
|
@ -903,8 +907,10 @@ CU_Test(ddsc_listener, data_available, .init=init_triggering_test, .fini=fini_tr
|
|||
|
||||
/* Deleting the writer causes unregisters (or dispose+unregister), and those
|
||||
should trigger DATA_AVAILABLE as well */
|
||||
ddsrt_mutex_lock(&g_mutex);
|
||||
cb_called = 0;
|
||||
cb_reader = 0;
|
||||
ddsrt_mutex_unlock(&g_mutex);
|
||||
ret = dds_delete (g_writer);
|
||||
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
|
||||
g_writer = 0;
|
||||
|
@ -942,8 +948,10 @@ CU_Test(ddsc_listener, data_available_delete_writer, .init=init_triggering_test,
|
|||
CU_ASSERT_EQUAL_FATAL(cb_reader, g_reader);
|
||||
|
||||
/* Deleting the writer must trigger DATA_AVAILABLE as well */
|
||||
ddsrt_mutex_lock(&g_mutex);
|
||||
cb_called = 0;
|
||||
cb_reader = 0;
|
||||
ddsrt_mutex_unlock(&g_mutex);
|
||||
ret = dds_delete (g_writer);
|
||||
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
|
||||
g_writer = 0;
|
||||
|
@ -991,8 +999,10 @@ CU_Test(ddsc_listener, data_available_delete_writer_disposed, .init=init_trigger
|
|||
} while (ret > 0);
|
||||
|
||||
/* Deleting the writer should not trigger DATA_AVAILABLE with all instances empty & disposed */
|
||||
ddsrt_mutex_lock(&g_mutex);
|
||||
cb_called = 0;
|
||||
cb_reader = 0;
|
||||
ddsrt_mutex_unlock(&g_mutex);
|
||||
ret = dds_delete (g_writer);
|
||||
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
|
||||
g_writer = 0;
|
||||
|
@ -1174,7 +1184,9 @@ CU_Test(ddsc_listener, liveliness_changed, .init=init_triggering_test, .fini=fin
|
|||
CU_ASSERT_EQUAL_FATAL(liveliness_changed.last_publication_handle, writer_hdl);
|
||||
|
||||
/* Reset the trigger flags. */
|
||||
ddsrt_mutex_lock(&g_mutex);
|
||||
cb_called = 0;
|
||||
ddsrt_mutex_unlock(&g_mutex);
|
||||
|
||||
/* Change liveliness again by deleting the writer. */
|
||||
dds_delete(g_writer);
|
||||
|
|
|
@ -47,7 +47,8 @@ CU_Test(ddsc_participant, create_with_no_conf_no_env)
|
|||
dds_domainid_t domain_id;
|
||||
dds_domainid_t valid_domain=3;
|
||||
|
||||
ddsrt_unsetenv(DDS_PROJECT_NAME_NOSPACE_CAPS"_URI");
|
||||
status = ddsrt_unsetenv(DDS_PROJECT_NAME_NOSPACE_CAPS"_URI");
|
||||
CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_OK);
|
||||
|
||||
//valid specific domain value
|
||||
participant2 = dds_create_participant (valid_domain, NULL, NULL);
|
||||
|
|
|
@ -277,7 +277,50 @@ CU_Theory((dds_entity_t *par, dds_entity_t *top), ddsc_reader_create, non_partic
|
|||
}
|
||||
/*************************************************************************************************/
|
||||
|
||||
/*************************************************************************************************/
|
||||
CU_Test(ddsc_reader_create, wrong_participant, .init=reader_init, .fini=reader_fini)
|
||||
{
|
||||
dds_entity_t participant2 = dds_create_participant(DDS_DOMAIN_DEFAULT, NULL, NULL);
|
||||
CU_ASSERT_FATAL(participant2 > 0);
|
||||
dds_entity_t reader = dds_create_reader(participant2, g_topic, NULL, NULL);
|
||||
CU_ASSERT_EQUAL_FATAL(reader, DDS_RETCODE_BAD_PARAMETER);
|
||||
dds_delete(participant2);
|
||||
}
|
||||
/*************************************************************************************************/
|
||||
|
||||
/*************************************************************************************************/
|
||||
CU_Test(ddsc_reader_create, participant_mismatch)
|
||||
{
|
||||
dds_entity_t par1 = 0;
|
||||
dds_entity_t par2 = 0;
|
||||
dds_entity_t sub1 = 0;
|
||||
dds_entity_t top2 = 0;
|
||||
dds_entity_t reader = 0;
|
||||
char name[100];
|
||||
|
||||
par1 = dds_create_participant(DDS_DOMAIN_DEFAULT, NULL, NULL);
|
||||
CU_ASSERT_FATAL(par1 > 0);
|
||||
par2 = dds_create_participant(DDS_DOMAIN_DEFAULT, NULL, NULL);
|
||||
CU_ASSERT_FATAL(par2 > 0);
|
||||
|
||||
sub1 = dds_create_subscriber(par1, NULL, NULL);
|
||||
CU_ASSERT_FATAL(sub1 > 0);
|
||||
|
||||
top2 = dds_create_topic(par2, &Space_Type1_desc, create_topic_name("ddsc_reader_participant_mismatch", name, sizeof name), NULL, NULL);
|
||||
CU_ASSERT_FATAL(top2 > 0);
|
||||
|
||||
/* Create reader with participant mismatch. */
|
||||
reader = dds_create_reader(sub1, top2, NULL, NULL);
|
||||
|
||||
/* Expect the creation to have failed. */
|
||||
CU_ASSERT_FATAL(reader <= 0);
|
||||
|
||||
dds_delete(top2);
|
||||
dds_delete(sub1);
|
||||
dds_delete(par2);
|
||||
dds_delete(par1);
|
||||
}
|
||||
/*************************************************************************************************/
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -256,6 +256,39 @@ CU_Theory((dds_entity_t *par), ddsc_waitset_create, non_participants, .init=ddsc
|
|||
}
|
||||
/*************************************************************************************************/
|
||||
|
||||
/*************************************************************************************************/
|
||||
CU_Test (ddsc_waitset_create, domain)
|
||||
{
|
||||
dds_entity_t par, dom, ws;
|
||||
dds_return_t rc;
|
||||
par = dds_create_participant (0, NULL, NULL);
|
||||
CU_ASSERT_FATAL (par > 0);
|
||||
dom = dds_get_parent (par);
|
||||
CU_ASSERT_FATAL (dom > 0);
|
||||
ws = dds_create_waitset (dom);
|
||||
CU_ASSERT_FATAL (ws > 0);
|
||||
rc = dds_delete (dom);
|
||||
CU_ASSERT_FATAL (rc == 0);
|
||||
}
|
||||
/*************************************************************************************************/
|
||||
|
||||
/*************************************************************************************************/
|
||||
CU_Test (ddsc_waitset_create, cyclonedds)
|
||||
{
|
||||
dds_entity_t ws;
|
||||
dds_return_t rc;
|
||||
/* Expect an uninitialised library */
|
||||
rc = dds_get_parent (DDS_CYCLONEDDS_HANDLE);
|
||||
CU_ASSERT_FATAL (rc == DDS_RETCODE_PRECONDITION_NOT_MET);
|
||||
ws = dds_create_waitset (DDS_CYCLONEDDS_HANDLE);
|
||||
CU_ASSERT_FATAL (ws > 0);
|
||||
rc = dds_delete (DDS_CYCLONEDDS_HANDLE);
|
||||
CU_ASSERT_FATAL (rc == 0);
|
||||
/* And the same afterward */
|
||||
rc = dds_get_parent (DDS_CYCLONEDDS_HANDLE);
|
||||
CU_ASSERT_FATAL (rc == DDS_RETCODE_PRECONDITION_NOT_MET);
|
||||
}
|
||||
/*************************************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************************************
|
||||
|
@ -318,6 +351,52 @@ CU_Test(ddsc_waitset_attach, deleted_waitset, .init=ddsc_waitset_basic_init, .fi
|
|||
}
|
||||
/*************************************************************************************************/
|
||||
|
||||
/*************************************************************************************************/
|
||||
CU_TheoryDataPoints(ddsc_waitset_attach, scoping) = {
|
||||
CU_DataPoints (int, -9, -1, -2, 0, 0, 2), /* owner: -9: lib, -1: dom0, -2: dom1 */
|
||||
CU_DataPoints (int, 0, 0, 2, 0, 0, 2), /* ok1: participant one can attach */
|
||||
CU_DataPoints (int, 3, 1, 3, -1, -1, -1), /* ok2: other participant one can attach, or -1 */
|
||||
CU_DataPoints (int, -1, 2, 0, 1, 2, 0), /* fail: participant that one cannot attach, or -1 */
|
||||
};
|
||||
CU_Theory ((int owner, int ok1, int ok2, int fail), ddsc_waitset_attach, scoping)
|
||||
{
|
||||
dds_entity_t par[4], dom[2], ws, ownh;
|
||||
dds_return_t rc;
|
||||
for (int i = 0; i < 2; i++) {
|
||||
for (int j = 0; j < 2; j++) {
|
||||
par[2*i+j] = dds_create_participant ((dds_domainid_t) i, NULL, NULL);
|
||||
CU_ASSERT_FATAL (par[2*i+j] > 0);
|
||||
}
|
||||
dom[i] = dds_get_parent (par[2*i]);
|
||||
CU_ASSERT_FATAL (dom[i] > 0);
|
||||
}
|
||||
if (owner == -9) {
|
||||
ownh = DDS_CYCLONEDDS_HANDLE;
|
||||
} else if (owner < 0) {
|
||||
ownh = dom[-owner - 1];
|
||||
} else {
|
||||
ownh = par[owner];
|
||||
}
|
||||
printf ("%d %d %d %d | %"PRId32"\n", owner, ok1, ok2, fail, ownh);
|
||||
ws = dds_create_waitset (ownh);
|
||||
CU_ASSERT_FATAL (ws > 0);
|
||||
rc = dds_waitset_attach (ws, par[ok1], 0);
|
||||
CU_ASSERT_FATAL (rc == 0);
|
||||
if (ok2 >= 0) {
|
||||
rc = dds_waitset_attach (ws, par[ok2], 1);
|
||||
CU_ASSERT_FATAL (rc == 0);
|
||||
}
|
||||
if (fail >= 0) {
|
||||
rc = dds_waitset_attach (ws, par[fail], 2);
|
||||
CU_ASSERT_FATAL (rc == DDS_RETCODE_BAD_PARAMETER);
|
||||
}
|
||||
rc = dds_delete (DDS_CYCLONEDDS_HANDLE);
|
||||
CU_ASSERT_FATAL (rc == 0);
|
||||
rc = dds_get_parent (DDS_CYCLONEDDS_HANDLE);
|
||||
CU_ASSERT_FATAL (rc == DDS_RETCODE_PRECONDITION_NOT_MET);
|
||||
}
|
||||
/*************************************************************************************************/
|
||||
|
||||
|
||||
|
||||
/**************************************************************************************************
|
||||
|
|
398
src/core/ddsc/tests/waitset_torture.c
Normal file
398
src/core/ddsc/tests/waitset_torture.c
Normal file
|
@ -0,0 +1,398 @@
|
|||
/*
|
||||
* Copyright(c) 2019 ADLINK Technology Limited and others
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
|
||||
* v. 1.0 which is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "dds/dds.h"
|
||||
#include "CUnit/Theory.h"
|
||||
#include "RoundTrip.h"
|
||||
|
||||
#include "dds/ddsrt/cdtors.h"
|
||||
#include "dds/ddsrt/misc.h"
|
||||
#include "dds/ddsrt/process.h"
|
||||
#include "dds/ddsrt/threads.h"
|
||||
#include "dds/ddsrt/atomics.h"
|
||||
#include "dds/ddsrt/time.h"
|
||||
#include "dds/ddsrt/random.h"
|
||||
|
||||
#define N_WAITSETS 20
|
||||
#define N_ENTITIES 32
|
||||
|
||||
#define N_GUARDCONDS 20
|
||||
#define N_SUBSCRIBERS 4
|
||||
#define N_READERS 4
|
||||
#define N_READCONDS 4
|
||||
|
||||
static dds_entity_t ppant;
|
||||
static dds_entity_t topic;
|
||||
|
||||
static ddsrt_atomic_uint32_t terminate;
|
||||
static ddsrt_atomic_uint32_t waitsets[N_WAITSETS];
|
||||
static ddsrt_atomic_uint32_t entities[N_ENTITIES], signalled;
|
||||
|
||||
static ddsrt_atomic_uint32_t attach_ok, detach_ok, settrig_ok;
|
||||
static ddsrt_atomic_uint32_t create_ent_ok[5], delete_ent_ok[5];
|
||||
static ddsrt_atomic_uint32_t create_ws_ok, delete_ws_ok;
|
||||
|
||||
#define RESERVED ((uint32_t) 0xffffffffu)
|
||||
|
||||
static void init_prng (ddsrt_prng_t *prng)
|
||||
{
|
||||
ddsrt_prng_seed_t prng_seed;
|
||||
for (size_t i = 0; i < sizeof (prng_seed.key) / sizeof (prng_seed.key[0]); i++)
|
||||
prng_seed.key[i] = ddsrt_random ();
|
||||
ddsrt_prng_init (prng, &prng_seed);
|
||||
}
|
||||
|
||||
static void choose_index (uint32_t *p_idx, uint32_t *p_handle, ddsrt_prng_t *prng, ddsrt_atomic_uint32_t elems[], size_t nelems)
|
||||
{
|
||||
uint32_t idx, h, h1;
|
||||
retry_idx:
|
||||
idx = ddsrt_prng_random (prng) % (uint32_t) nelems;
|
||||
retry_cas:
|
||||
h = ddsrt_atomic_ld32 (&elems[idx]);
|
||||
if (h == 0)
|
||||
h1 = RESERVED;
|
||||
else if ((int32_t) h > 0)
|
||||
h1 = 0;
|
||||
else
|
||||
goto retry_idx;
|
||||
if (!ddsrt_atomic_cas32 (&elems[idx], h, h1))
|
||||
goto retry_cas;
|
||||
*p_idx = idx;
|
||||
*p_handle = h;
|
||||
}
|
||||
|
||||
static dds_entity_t pick_a_subscriber (void)
|
||||
{
|
||||
uint32_t idx = ddsrt_random () % N_SUBSCRIBERS;
|
||||
uint32_t x = ddsrt_atomic_ld32 (&entities[N_GUARDCONDS + idx]);
|
||||
return (dds_entity_t) x;
|
||||
}
|
||||
|
||||
static dds_entity_t pick_a_reader (void)
|
||||
{
|
||||
uint32_t idx = ddsrt_random () % N_READERS;
|
||||
uint32_t x = ddsrt_atomic_ld32 (&entities[N_GUARDCONDS + N_SUBSCRIBERS + idx]);
|
||||
return (dds_entity_t) x;
|
||||
}
|
||||
|
||||
static int index_to_counter_index (uint32_t idx)
|
||||
{
|
||||
if (idx < N_GUARDCONDS)
|
||||
return 0;
|
||||
else if (idx < N_GUARDCONDS + N_SUBSCRIBERS)
|
||||
return 1;
|
||||
else if (idx < N_GUARDCONDS + N_SUBSCRIBERS + N_READERS)
|
||||
return 2;
|
||||
else
|
||||
return 4;
|
||||
}
|
||||
|
||||
static uint32_t guardcond_create_delete_thread (void *varg)
|
||||
{
|
||||
(void) varg;
|
||||
ddsrt_prng_t prng;
|
||||
init_prng (&prng);
|
||||
while (!ddsrt_atomic_ld32 (&terminate))
|
||||
{
|
||||
uint32_t idx, handle;
|
||||
choose_index (&idx, &handle, &prng, entities, N_ENTITIES);
|
||||
if (handle == 0)
|
||||
{
|
||||
dds_entity_t ent = 0, parent = 0;
|
||||
|
||||
if (idx < N_GUARDCONDS)
|
||||
ent = dds_create_guardcondition (DDS_CYCLONEDDS_HANDLE);
|
||||
else if (idx < N_GUARDCONDS + N_SUBSCRIBERS)
|
||||
ent = dds_create_subscriber (ppant, NULL, NULL);
|
||||
else if (idx < N_GUARDCONDS + N_SUBSCRIBERS + N_READERS)
|
||||
{
|
||||
if ((parent = pick_a_subscriber ()) == 0)
|
||||
parent = ppant;
|
||||
ent = dds_create_reader (parent, topic, NULL, NULL);
|
||||
}
|
||||
else if ((parent = pick_a_reader ()) != 0)
|
||||
{
|
||||
ent = dds_create_readcondition (parent, DDS_ANY_STATE);
|
||||
}
|
||||
|
||||
if (ent > 0)
|
||||
{
|
||||
ddsrt_atomic_inc32 (&create_ent_ok[index_to_counter_index (idx) + (parent == ppant)]);
|
||||
ddsrt_atomic_st32 (&entities[idx], (uint32_t) ent);
|
||||
}
|
||||
else if (ent < 0 && idx < N_GUARDCONDS)
|
||||
{
|
||||
fprintf (stderr, "dds_create_guardcondition failed: %s\n", dds_strretcode (ent));
|
||||
ddsrt_atomic_st32 (&terminate, 1);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dds_return_t rc = dds_delete ((dds_entity_t) handle);
|
||||
if (rc == 0)
|
||||
ddsrt_atomic_inc32 (&delete_ent_ok[index_to_counter_index (idx)]);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t waitset_create_delete_thread (void *varg)
|
||||
{
|
||||
(void) varg;
|
||||
ddsrt_prng_t prng;
|
||||
init_prng (&prng);
|
||||
while (!ddsrt_atomic_ld32 (&terminate))
|
||||
{
|
||||
uint32_t idx, handle;
|
||||
choose_index (&idx, &handle, &prng, waitsets, N_WAITSETS);
|
||||
if (handle == 0)
|
||||
{
|
||||
dds_entity_t ws = dds_create_waitset (DDS_CYCLONEDDS_HANDLE);
|
||||
if (ws < 0)
|
||||
{
|
||||
fprintf (stderr, "dds_create_waitset failed: %s\n", dds_strretcode (ws));
|
||||
ddsrt_atomic_st32 (&terminate, 1);
|
||||
return 1;
|
||||
}
|
||||
ddsrt_atomic_inc32 (&create_ws_ok);
|
||||
ddsrt_atomic_st32 (&waitsets[idx], (uint32_t) ws);
|
||||
}
|
||||
else
|
||||
{
|
||||
dds_return_t rc = dds_delete ((dds_entity_t) handle);
|
||||
if (rc == 0)
|
||||
ddsrt_atomic_inc32 (&delete_ws_ok);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t guardcond_trigger_thread (void *varg)
|
||||
{
|
||||
(void) varg;
|
||||
ddsrt_prng_t prng;
|
||||
init_prng (&prng);
|
||||
while (!ddsrt_atomic_ld32 (&terminate))
|
||||
{
|
||||
uint32_t idx = ddsrt_prng_random (&prng) % N_ENTITIES;
|
||||
uint32_t h = ddsrt_atomic_ld32 (&entities[idx]);
|
||||
if ((int32_t) h <= 0)
|
||||
continue;
|
||||
else
|
||||
{
|
||||
uint32_t s, s1;
|
||||
do {
|
||||
s = ddsrt_atomic_ld32 (&signalled);
|
||||
s1 = s ^ (1u << idx);
|
||||
} while (!ddsrt_atomic_cas32 (&signalled, s, s1));
|
||||
dds_return_t rc = dds_set_guardcondition ((dds_entity_t) h, (s & (1u << idx)) ? false : true);
|
||||
if (rc == 0)
|
||||
ddsrt_atomic_inc32 (&settrig_ok);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t waitset_attach_detach_thread (void *varg)
|
||||
{
|
||||
(void) varg;
|
||||
ddsrt_prng_t prng;
|
||||
init_prng (&prng);
|
||||
while (!ddsrt_atomic_ld32 (&terminate))
|
||||
{
|
||||
uint32_t wsidx = ddsrt_prng_random (&prng) % N_WAITSETS;
|
||||
uint32_t wsh = ddsrt_atomic_ld32 (&waitsets[wsidx]);
|
||||
if ((int32_t) wsh <= 0)
|
||||
continue;
|
||||
|
||||
uint32_t gcidx = ddsrt_prng_random (&prng) % N_ENTITIES;
|
||||
uint32_t gch = ddsrt_atomic_ld32 (&entities[gcidx]);
|
||||
if ((int32_t) gch <= 0)
|
||||
continue;
|
||||
|
||||
dds_return_t rc;
|
||||
rc = dds_waitset_detach ((dds_entity_t) wsh, (dds_entity_t) gch);
|
||||
if (rc == 0)
|
||||
{
|
||||
ddsrt_atomic_inc32 (&detach_ok);
|
||||
}
|
||||
else if (rc != DDS_RETCODE_PRECONDITION_NOT_MET && rc != DDS_RETCODE_BAD_PARAMETER)
|
||||
{
|
||||
/* attempts at attaching a guard condition twice or detaching an unattached
|
||||
one are expected, and those result in a PRECONDITION_NOT_MET */
|
||||
fprintf (stderr, "dds_waitset_detach 0x%"PRIx32" 0x%"PRIx32" failed: %s\n", (dds_entity_t) wsh, (dds_entity_t) gch, dds_strretcode (rc));
|
||||
ddsrt_atomic_st32 (&terminate, 1);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* should imply it is already attached, so try detaching */
|
||||
rc = dds_waitset_attach ((dds_entity_t) wsh, (dds_entity_t) gch, 0);
|
||||
if (rc == 0)
|
||||
{
|
||||
ddsrt_atomic_inc32 (&attach_ok);
|
||||
}
|
||||
else if (rc != DDS_RETCODE_PRECONDITION_NOT_MET && rc != DDS_RETCODE_BAD_PARAMETER)
|
||||
{
|
||||
fprintf (stderr, "dds_waitset_attach 0x%"PRIx32" 0x%"PRIx32" failed: %s\n", (dds_entity_t) wsh, (dds_entity_t) gch, dds_strretcode (rc));
|
||||
ddsrt_atomic_st32 (&terminate, 1);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
CU_Test (ddsc_waitset, torture)
|
||||
{
|
||||
dds_return_t rc;
|
||||
ddsrt_thread_t tids[8];
|
||||
ddsrt_threadattr_t tattr;
|
||||
ddsrt_threadattr_init (&tattr);
|
||||
|
||||
/* This keeps the library initialised -- it shouldn't be necessary */
|
||||
ppant = dds_create_participant (DDS_DOMAIN_DEFAULT, NULL, NULL);
|
||||
CU_ASSERT_FATAL (ppant > 0);
|
||||
topic = dds_create_topic (ppant, &RoundTripModule_DataType_desc, "waitset_torture_topic", NULL, NULL);
|
||||
CU_ASSERT_FATAL (topic > 0);
|
||||
|
||||
rc = ddsrt_thread_create (&tids[0], "gc_cd", &tattr, guardcond_create_delete_thread, 0);
|
||||
CU_ASSERT_FATAL (rc == 0);
|
||||
rc = ddsrt_thread_create (&tids[1], "gc_cd", &tattr, guardcond_create_delete_thread, 0);
|
||||
CU_ASSERT_FATAL (rc == 0);
|
||||
rc = ddsrt_thread_create (&tids[2], "ws_cd", &tattr, waitset_create_delete_thread, 0);
|
||||
CU_ASSERT_FATAL (rc == 0);
|
||||
rc = ddsrt_thread_create (&tids[3], "ws_cd", &tattr, waitset_create_delete_thread, 0);
|
||||
CU_ASSERT_FATAL (rc == 0);
|
||||
rc = ddsrt_thread_create (&tids[4], "gc_t", &tattr, guardcond_trigger_thread, 0);
|
||||
CU_ASSERT_FATAL (rc == 0);
|
||||
rc = ddsrt_thread_create (&tids[5], "gc_t", &tattr, guardcond_trigger_thread, 0);
|
||||
CU_ASSERT_FATAL (rc == 0);
|
||||
rc = ddsrt_thread_create (&tids[6], "ws_ad", &tattr, waitset_attach_detach_thread, 0);
|
||||
CU_ASSERT_FATAL (rc == 0);
|
||||
rc = ddsrt_thread_create (&tids[7], "ws_ad", &tattr, waitset_attach_detach_thread, 0);
|
||||
CU_ASSERT_FATAL (rc == 0);
|
||||
|
||||
uint32_t wait_err = 0, wait_ok[N_ENTITIES + 1] = { 0 };
|
||||
dds_time_t tstop = dds_time () + DDS_SECS (5);
|
||||
while (dds_time () < tstop && !ddsrt_atomic_ld32 (&terminate))
|
||||
{
|
||||
/* Try waiting on the waitset in slot 0 if it exists (it shouldn't make much
|
||||
difference which waitset we use; this is easy). There are never more than
|
||||
N_ENTITIES guard conditions, so there are also never more than that many
|
||||
triggering entities, and so we can easily do a small histogram. (The longer
|
||||
you run it, the longer the tail of triggering entities one expects.)
|
||||
|
||||
Error handling: the waitset may be deleted in between loading the handle
|
||||
and pinning it wait(), so BAD_PARAMETER is to be expected. If the "extragc"
|
||||
isn't there to ensure the library stays initialised, it is even possible
|
||||
that we get PRECONDITION_NOT_MET if it just so happened that with the
|
||||
deleting of that waitset, no entities remain at all. */
|
||||
dds_entity_t ws = (dds_entity_t) ddsrt_atomic_ld32 (&waitsets[0]);
|
||||
if (ws > 0)
|
||||
{
|
||||
int32_t n = dds_waitset_wait (ws, NULL, 0, DDS_MSECS (10));
|
||||
if (!((rc >= 0 && rc <= N_ENTITIES) || rc == DDS_RETCODE_BAD_PARAMETER))
|
||||
{
|
||||
fprintf (stderr, "dds_waitset_wait failed: %s\n", dds_strretcode (rc));
|
||||
ddsrt_atomic_st32 (&terminate, 1);
|
||||
rc = DDS_RETCODE_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (n >= 0)
|
||||
wait_ok[n]++;
|
||||
else
|
||||
wait_err++;
|
||||
}
|
||||
}
|
||||
}
|
||||
ddsrt_atomic_st32 (&terminate, 1);
|
||||
CU_ASSERT (rc != DDS_RETCODE_ERROR);
|
||||
|
||||
for (size_t i = 0; i < sizeof (tids) / sizeof (tids[0]); i++)
|
||||
{
|
||||
uint32_t retval;
|
||||
rc = ddsrt_thread_join (tids[i], &retval);
|
||||
CU_ASSERT_FATAL (rc == 0);
|
||||
CU_ASSERT (retval == 0);
|
||||
}
|
||||
|
||||
/* The threads don't bother to clean up, so delete whatever guard conditions and
|
||||
waitsets happen to still exist. Passing garbage into dds_delete is supposed
|
||||
to work, so don't bother with any validation or error checking. */
|
||||
for (uint32_t i = 0; i < N_ENTITIES; i++)
|
||||
{
|
||||
if (dds_delete ((dds_entity_t) ddsrt_atomic_ld32 (&entities[i])) == DDS_RETCODE_OK)
|
||||
ddsrt_atomic_inc32 (&delete_ent_ok[index_to_counter_index (i)]);
|
||||
}
|
||||
for (uint32_t i = 0; i < N_WAITSETS; i++)
|
||||
{
|
||||
if (dds_delete ((dds_entity_t) ddsrt_atomic_ld32 (&waitsets[i])) == DDS_RETCODE_OK)
|
||||
ddsrt_atomic_inc32 (&delete_ws_ok);
|
||||
}
|
||||
|
||||
/* All we should be left within the participant is the topic */
|
||||
rc = dds_delete (topic);
|
||||
CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
|
||||
rc = dds_get_children (ppant, NULL, 0);
|
||||
CU_ASSERT_FATAL (rc == 0);
|
||||
rc = dds_delete (ppant);
|
||||
CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
|
||||
|
||||
printf ("attach %"PRIu32" detach %"PRIu32" settrig %"PRIu32"\n", ddsrt_atomic_ld32 (&attach_ok), ddsrt_atomic_ld32 (&detach_ok), ddsrt_atomic_ld32 (&settrig_ok));
|
||||
printf ("create/delete ent");
|
||||
uint32_t create_ent_ok_sum = 0;
|
||||
for (size_t i = 0; i < sizeof (create_ent_ok) / sizeof (create_ent_ok[0]); i++)
|
||||
{
|
||||
uint32_t c = ddsrt_atomic_ld32 (&create_ent_ok[i]);
|
||||
create_ent_ok_sum += c;
|
||||
printf (" %"PRIu32"/%"PRIu32, c, ddsrt_atomic_ld32 (&delete_ent_ok[i]));
|
||||
}
|
||||
printf ("\n");
|
||||
|
||||
{
|
||||
uint32_t rd_cr_sub = ddsrt_atomic_ld32 (&create_ent_ok[2]);
|
||||
uint32_t rd_cr_ppant = ddsrt_atomic_ld32 (&create_ent_ok[3]);
|
||||
uint32_t rd_del = ddsrt_atomic_ld32 (&delete_ent_ok[2]);
|
||||
uint32_t sub_del = ddsrt_atomic_ld32 (&delete_ent_ok[1]);
|
||||
CU_ASSERT (rd_del <= rd_cr_sub + rd_cr_ppant); /* can't have deleted more readers than were created */
|
||||
CU_ASSERT (rd_del >= rd_cr_ppant); /* readers created with ppant as owner must have been deleted explicitly */
|
||||
CU_ASSERT (rd_del - rd_cr_ppant <= sub_del); /* other readers may have been deleted by deleting a sub */
|
||||
}
|
||||
|
||||
printf ("create/delete ws %"PRIu32"/%"PRIu32"\n", ddsrt_atomic_ld32 (&create_ws_ok), ddsrt_atomic_ld32 (&delete_ws_ok));
|
||||
printf ("wait {err %"PRIu32"}", wait_err);
|
||||
uint32_t wait_ok_sum = 0;
|
||||
for (size_t i = 0; i < sizeof (wait_ok) / sizeof (wait_ok[0]); i++)
|
||||
{
|
||||
wait_ok_sum += wait_ok[i];
|
||||
printf (" %"PRIu32, wait_ok[i]);
|
||||
}
|
||||
printf ("\n");
|
||||
|
||||
/* Running on Windows on the CI infrastructure has very little concurrency, but Linux
|
||||
and macOS seem ok. The thresholds here appear to be sufficiently low to not give
|
||||
many spurious failures, while still being sanity check that at least something
|
||||
happened. */
|
||||
CU_ASSERT (ddsrt_atomic_ld32 (&attach_ok) +
|
||||
ddsrt_atomic_ld32 (&settrig_ok) +
|
||||
ddsrt_atomic_ld32 (&create_ws_ok) +
|
||||
create_ent_ok_sum +
|
||||
wait_ok_sum > 1000);
|
||||
|
||||
rc = dds_get_parent (DDS_CYCLONEDDS_HANDLE);
|
||||
CU_ASSERT_FATAL (rc == DDS_RETCODE_PRECONDITION_NOT_MET);
|
||||
}
|
|
@ -72,6 +72,15 @@ CU_Test(ddsc_create_writer, participant, .init = setup, .fini = teardown)
|
|||
CU_ASSERT_FATAL(writer > 0);
|
||||
}
|
||||
|
||||
CU_Test(ddsc_create_writer, wrong_participant, .init = setup, .fini = teardown)
|
||||
{
|
||||
dds_entity_t participant2 = dds_create_participant(DDS_DOMAIN_DEFAULT, NULL, NULL);
|
||||
CU_ASSERT_FATAL(participant2 > 0);
|
||||
writer = dds_create_writer(participant2, topic, NULL, NULL);
|
||||
CU_ASSERT_EQUAL_FATAL(writer, DDS_RETCODE_BAD_PARAMETER);
|
||||
dds_delete(participant2);
|
||||
}
|
||||
|
||||
CU_Test(ddsc_create_writer, publisher, .init = setup, .fini = teardown)
|
||||
{
|
||||
writer = dds_create_writer(publisher, topic, NULL, NULL);
|
||||
|
@ -107,3 +116,27 @@ CU_Test(ddsc_create_writer, deleted_topic, .init = setup, .fini = teardown)
|
|||
writer = dds_create_writer(publisher, topic, NULL, NULL);
|
||||
CU_ASSERT_EQUAL_FATAL(writer, DDS_RETCODE_BAD_PARAMETER);
|
||||
}
|
||||
|
||||
|
||||
CU_Test(ddsc_create_writer, participant_mismatch, .init = setup, .fini = teardown)
|
||||
{
|
||||
dds_entity_t l_par = 0;
|
||||
dds_entity_t l_pub = 0;
|
||||
|
||||
/* The call to setup() created the global topic. */
|
||||
|
||||
/* Create publisher on local participant. */
|
||||
l_par = dds_create_participant(DDS_DOMAIN_DEFAULT, NULL, NULL);
|
||||
CU_ASSERT_FATAL(l_par > 0);
|
||||
l_pub = dds_create_publisher(l_par, NULL, NULL);
|
||||
CU_ASSERT_FATAL(l_pub > 0);
|
||||
|
||||
/* Create writer with local publisher and global topic. */
|
||||
writer = dds_create_writer(l_pub, topic, NULL, NULL);
|
||||
|
||||
/* Expect the creation to have failed. */
|
||||
CU_ASSERT_FATAL(writer <= 0);
|
||||
|
||||
dds_delete(l_pub);
|
||||
dds_delete(l_par);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue