Merge branch 'master' into security
This commit is contained in:
		
						commit
						35ce7788e1
					
				
					 54 changed files with 2115 additions and 1069 deletions
				
			
		| 
						 | 
				
			
			@ -20,9 +20,12 @@ struct dds_rhc;
 | 
			
		|||
struct dds_reader;
 | 
			
		||||
struct ddsi_sertopic;
 | 
			
		||||
struct q_globals;
 | 
			
		||||
struct dds_rhc_default;
 | 
			
		||||
struct rhc_sample;
 | 
			
		||||
 | 
			
		||||
DDS_EXPORT struct dds_rhc *dds_rhc_default_new_xchecks (dds_reader *reader, struct q_globals *gv, const struct ddsi_sertopic *topic, bool xchecks);
 | 
			
		||||
DDS_EXPORT struct dds_rhc *dds_rhc_default_new (struct dds_reader *reader, const struct ddsi_sertopic *topic);
 | 
			
		||||
DDS_EXPORT nn_mtime_t dds_rhc_default_sample_expired_cb(void *hc, nn_mtime_t tnow);
 | 
			
		||||
 | 
			
		||||
#if defined (__cplusplus)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,7 +19,7 @@
 | 
			
		|||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
struct whc *builtintopic_whc_new (enum ddsi_sertopic_builtintopic_type type, const struct ephash *guid_hash);
 | 
			
		||||
struct whc *builtintopic_whc_new (enum ddsi_sertopic_builtintopic_type type, const struct entity_index *entidx);
 | 
			
		||||
 | 
			
		||||
#if defined (__cplusplus)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -257,10 +257,12 @@ void dds__builtin_init (struct dds_domain *dom)
 | 
			
		|||
  dom->builtin_reader_topic = new_sertopic_builtintopic (DSBT_READER, "DCPSSubscription", "org::eclipse::cyclonedds::builtin::DCPSSubscription", &dom->gv);
 | 
			
		||||
  dom->builtin_writer_topic = new_sertopic_builtintopic (DSBT_WRITER, "DCPSPublication", "org::eclipse::cyclonedds::builtin::DCPSPublication", &dom->gv);
 | 
			
		||||
 | 
			
		||||
  const struct ephash *gh = dom->gv.guid_hash;
 | 
			
		||||
  thread_state_awake (lookup_thread_state (), &dom->gv);
 | 
			
		||||
  const struct entity_index *gh = dom->gv.entity_index;
 | 
			
		||||
  dom->builtintopic_writer_participant = new_local_orphan_writer (&dom->gv, to_entityid (NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_WRITER), dom->builtin_participant_topic, qos, builtintopic_whc_new (DSBT_PARTICIPANT, gh));
 | 
			
		||||
  dom->builtintopic_writer_publications = new_local_orphan_writer (&dom->gv, to_entityid (NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_WRITER), dom->builtin_writer_topic, qos, builtintopic_whc_new (DSBT_WRITER, gh));
 | 
			
		||||
  dom->builtintopic_writer_subscriptions = new_local_orphan_writer (&dom->gv, to_entityid (NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_WRITER), dom->builtin_reader_topic, qos, builtintopic_whc_new (DSBT_READER, gh));
 | 
			
		||||
  thread_state_asleep (lookup_thread_state ());
 | 
			
		||||
 | 
			
		||||
  dds_delete_qos (qos);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,7 +16,7 @@
 | 
			
		|||
#include "dds__guardcond.h"
 | 
			
		||||
#include "dds__participant.h"
 | 
			
		||||
#include "dds/ddsi/ddsi_iid.h"
 | 
			
		||||
#include "dds/ddsi/q_ephash.h"
 | 
			
		||||
#include "dds/ddsi/ddsi_entity_index.h"
 | 
			
		||||
#include "dds/ddsi/q_entity.h"
 | 
			
		||||
#include "dds/ddsi/q_thread.h"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,6 +17,7 @@
 | 
			
		|||
#include "dds/ddsi/q_config.h"
 | 
			
		||||
#include "dds/ddsi/q_globals.h"
 | 
			
		||||
#include "dds/ddsi/q_entity.h"
 | 
			
		||||
#include "dds/ddsi/ddsi_entity_index.h"
 | 
			
		||||
#include "dds/ddsi/q_thread.h"
 | 
			
		||||
#include "dds/ddsi/q_bswap.h"
 | 
			
		||||
#include "dds__writer.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -33,7 +34,7 @@ dds_return_t dds_get_matched_subscriptions (dds_entity_t writer, dds_instance_ha
 | 
			
		|||
    return rc;
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
    const struct ephash *gh = wr->m_entity.m_domain->gv.guid_hash;
 | 
			
		||||
    const struct entity_index *gh = wr->m_entity.m_domain->gv.entity_index;
 | 
			
		||||
    size_t nrds_act = 0;
 | 
			
		||||
    ddsrt_avl_iter_t it;
 | 
			
		||||
    /* FIXME: this ought not be so tightly coupled to the lower layer */
 | 
			
		||||
| 
						 | 
				
			
			@ -44,7 +45,7 @@ dds_return_t dds_get_matched_subscriptions (dds_entity_t writer, dds_instance_ha
 | 
			
		|||
         m = ddsrt_avl_iter_next (&it))
 | 
			
		||||
    {
 | 
			
		||||
      struct proxy_reader *prd;
 | 
			
		||||
      if ((prd = ephash_lookup_proxy_reader_guid (gh, &m->prd_guid)) != NULL)
 | 
			
		||||
      if ((prd = entidx_lookup_proxy_reader_guid (gh, &m->prd_guid)) != NULL)
 | 
			
		||||
      {
 | 
			
		||||
        if (nrds_act < nrds)
 | 
			
		||||
          rds[nrds_act] = prd->e.iid;
 | 
			
		||||
| 
						 | 
				
			
			@ -56,7 +57,7 @@ dds_return_t dds_get_matched_subscriptions (dds_entity_t writer, dds_instance_ha
 | 
			
		|||
         m = ddsrt_avl_iter_next (&it))
 | 
			
		||||
    {
 | 
			
		||||
      struct reader *rd;
 | 
			
		||||
      if ((rd = ephash_lookup_reader_guid (gh, &m->rd_guid)) != NULL)
 | 
			
		||||
      if ((rd = entidx_lookup_reader_guid (gh, &m->rd_guid)) != NULL)
 | 
			
		||||
      {
 | 
			
		||||
        if (nrds_act < nrds)
 | 
			
		||||
          rds[nrds_act] = rd->e.iid;
 | 
			
		||||
| 
						 | 
				
			
			@ -83,7 +84,7 @@ dds_return_t dds_get_matched_publications (dds_entity_t reader, dds_instance_han
 | 
			
		|||
    return rc;
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
    const struct ephash *gh = rd->m_entity.m_domain->gv.guid_hash;
 | 
			
		||||
    const struct entity_index *gh = rd->m_entity.m_domain->gv.entity_index;
 | 
			
		||||
    size_t nwrs_act = 0;
 | 
			
		||||
    ddsrt_avl_iter_t it;
 | 
			
		||||
    /* FIXME: this ought not be so tightly coupled to the lower layer */
 | 
			
		||||
| 
						 | 
				
			
			@ -94,7 +95,7 @@ dds_return_t dds_get_matched_publications (dds_entity_t reader, dds_instance_han
 | 
			
		|||
         m = ddsrt_avl_iter_next (&it))
 | 
			
		||||
    {
 | 
			
		||||
      struct proxy_writer *pwr;
 | 
			
		||||
      if ((pwr = ephash_lookup_proxy_writer_guid (gh, &m->pwr_guid)) != NULL)
 | 
			
		||||
      if ((pwr = entidx_lookup_proxy_writer_guid (gh, &m->pwr_guid)) != NULL)
 | 
			
		||||
      {
 | 
			
		||||
        if (nwrs_act < nwrs)
 | 
			
		||||
          wrs[nwrs_act] = pwr->e.iid;
 | 
			
		||||
| 
						 | 
				
			
			@ -106,7 +107,7 @@ dds_return_t dds_get_matched_publications (dds_entity_t reader, dds_instance_han
 | 
			
		|||
         m = ddsrt_avl_iter_next (&it))
 | 
			
		||||
    {
 | 
			
		||||
      struct writer *wr;
 | 
			
		||||
      if ((wr = ephash_lookup_writer_guid (gh, &m->wr_guid)) != NULL)
 | 
			
		||||
      if ((wr = entidx_lookup_writer_guid (gh, &m->wr_guid)) != NULL)
 | 
			
		||||
      {
 | 
			
		||||
        if (nwrs_act < nwrs)
 | 
			
		||||
          wrs[nwrs_act] = wr->e.iid;
 | 
			
		||||
| 
						 | 
				
			
			@ -148,7 +149,7 @@ dds_builtintopic_endpoint_t *dds_get_matched_subscription_data (dds_entity_t wri
 | 
			
		|||
    return NULL;
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
    const struct ephash *gh = wr->m_entity.m_domain->gv.guid_hash;
 | 
			
		||||
    const struct entity_index *gh = wr->m_entity.m_domain->gv.entity_index;
 | 
			
		||||
    dds_builtintopic_endpoint_t *ret = NULL;
 | 
			
		||||
    ddsrt_avl_iter_t it;
 | 
			
		||||
    /* FIXME: this ought not be so tightly coupled to the lower layer, and not be so inefficient besides */
 | 
			
		||||
| 
						 | 
				
			
			@ -159,7 +160,7 @@ dds_builtintopic_endpoint_t *dds_get_matched_subscription_data (dds_entity_t wri
 | 
			
		|||
         m = ddsrt_avl_iter_next (&it))
 | 
			
		||||
    {
 | 
			
		||||
      struct proxy_reader *prd;
 | 
			
		||||
      if ((prd = ephash_lookup_proxy_reader_guid (gh, &m->prd_guid)) != NULL)
 | 
			
		||||
      if ((prd = entidx_lookup_proxy_reader_guid (gh, &m->prd_guid)) != NULL)
 | 
			
		||||
      {
 | 
			
		||||
        if (prd->e.iid == ih)
 | 
			
		||||
          ret = make_builtintopic_endpoint (&prd->e.guid, &prd->c.proxypp->e.guid, prd->c.proxypp->e.iid, prd->c.xqos);
 | 
			
		||||
| 
						 | 
				
			
			@ -170,7 +171,7 @@ dds_builtintopic_endpoint_t *dds_get_matched_subscription_data (dds_entity_t wri
 | 
			
		|||
         m = ddsrt_avl_iter_next (&it))
 | 
			
		||||
    {
 | 
			
		||||
      struct reader *rd;
 | 
			
		||||
      if ((rd = ephash_lookup_reader_guid (gh, &m->rd_guid)) != NULL)
 | 
			
		||||
      if ((rd = entidx_lookup_reader_guid (gh, &m->rd_guid)) != NULL)
 | 
			
		||||
      {
 | 
			
		||||
        if (rd->e.iid == ih)
 | 
			
		||||
          ret = make_builtintopic_endpoint (&rd->e.guid, &rd->c.pp->e.guid, rd->c.pp->e.iid, rd->xqos);
 | 
			
		||||
| 
						 | 
				
			
			@ -191,7 +192,7 @@ dds_builtintopic_endpoint_t *dds_get_matched_publication_data (dds_entity_t read
 | 
			
		|||
    return NULL;
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
    const struct ephash *gh = rd->m_entity.m_domain->gv.guid_hash;
 | 
			
		||||
    const struct entity_index *gh = rd->m_entity.m_domain->gv.entity_index;
 | 
			
		||||
    dds_builtintopic_endpoint_t *ret = NULL;
 | 
			
		||||
    ddsrt_avl_iter_t it;
 | 
			
		||||
    /* FIXME: this ought not be so tightly coupled to the lower layer, and not be so inefficient besides */
 | 
			
		||||
| 
						 | 
				
			
			@ -202,7 +203,7 @@ dds_builtintopic_endpoint_t *dds_get_matched_publication_data (dds_entity_t read
 | 
			
		|||
         m = ddsrt_avl_iter_next (&it))
 | 
			
		||||
    {
 | 
			
		||||
      struct proxy_writer *pwr;
 | 
			
		||||
      if ((pwr = ephash_lookup_proxy_writer_guid (gh, &m->pwr_guid)) != NULL)
 | 
			
		||||
      if ((pwr = entidx_lookup_proxy_writer_guid (gh, &m->pwr_guid)) != NULL)
 | 
			
		||||
      {
 | 
			
		||||
        if (pwr->e.iid == ih)
 | 
			
		||||
          ret = make_builtintopic_endpoint (&pwr->e.guid, &pwr->c.proxypp->e.guid, pwr->c.proxypp->e.iid, pwr->c.xqos);
 | 
			
		||||
| 
						 | 
				
			
			@ -213,7 +214,7 @@ dds_builtintopic_endpoint_t *dds_get_matched_publication_data (dds_entity_t read
 | 
			
		|||
         m = ddsrt_avl_iter_next (&it))
 | 
			
		||||
    {
 | 
			
		||||
      struct writer *wr;
 | 
			
		||||
      if ((wr = ephash_lookup_writer_guid (gh, &m->wr_guid)) != NULL)
 | 
			
		||||
      if ((wr = entidx_lookup_writer_guid (gh, &m->wr_guid)) != NULL)
 | 
			
		||||
      {
 | 
			
		||||
        if (wr->e.iid == ih)
 | 
			
		||||
          ret = make_builtintopic_endpoint (&wr->e.guid, &wr->c.pp->e.guid, wr->c.pp->e.iid, wr->xqos);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,6 +18,7 @@
 | 
			
		|||
#include "dds/ddsi/q_config.h"
 | 
			
		||||
#include "dds/ddsi/q_plist.h"
 | 
			
		||||
#include "dds/ddsi/q_globals.h"
 | 
			
		||||
#include "dds/ddsi/ddsi_entity_index.h"
 | 
			
		||||
#include "dds/version.h"
 | 
			
		||||
#include "dds__init.h"
 | 
			
		||||
#include "dds__domain.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -55,7 +56,7 @@ static dds_return_t dds_participant_qos_set (dds_entity *e, const dds_qos_t *qos
 | 
			
		|||
  {
 | 
			
		||||
    struct participant *pp;
 | 
			
		||||
    thread_state_awake (lookup_thread_state (), &e->m_domain->gv);
 | 
			
		||||
    if ((pp = ephash_lookup_participant_guid (e->m_domain->gv.guid_hash, &e->m_guid)) != NULL)
 | 
			
		||||
    if ((pp = entidx_lookup_participant_guid (e->m_domain->gv.entity_index, &e->m_guid)) != NULL)
 | 
			
		||||
    {
 | 
			
		||||
      nn_plist_t plist;
 | 
			
		||||
      nn_plist_init_empty (&plist);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,7 +16,7 @@
 | 
			
		|||
#include "dds/ddsi/ddsi_tkmap.h"
 | 
			
		||||
#include "dds/ddsc/dds_rhc.h"
 | 
			
		||||
#include "dds/ddsi/q_thread.h"
 | 
			
		||||
#include "dds/ddsi/q_ephash.h"
 | 
			
		||||
#include "dds/ddsi/ddsi_entity_index.h"
 | 
			
		||||
#include "dds/ddsi/q_entity.h"
 | 
			
		||||
#include "dds/ddsi/q_globals.h"
 | 
			
		||||
#include "dds/ddsi/ddsi_sertopic.h"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,7 +15,7 @@
 | 
			
		|||
#include "dds/ddsc/dds_rhc.h"
 | 
			
		||||
#include "dds__entity.h"
 | 
			
		||||
#include "dds/ddsi/ddsi_iid.h"
 | 
			
		||||
#include "dds/ddsi/q_ephash.h"
 | 
			
		||||
#include "dds/ddsi/ddsi_entity_index.h"
 | 
			
		||||
#include "dds/ddsi/q_entity.h"
 | 
			
		||||
#include "dds/ddsi/q_thread.h"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,6 +28,7 @@
 | 
			
		|||
#include "dds/ddsi/q_globals.h"
 | 
			
		||||
#include "dds__builtin.h"
 | 
			
		||||
#include "dds/ddsi/ddsi_sertopic.h"
 | 
			
		||||
#include "dds/ddsi/ddsi_entity_index.h"
 | 
			
		||||
 | 
			
		||||
DECL_ENTITY_LOCK_UNLOCK (extern inline, dds_reader)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -77,7 +78,7 @@ static dds_return_t dds_reader_qos_set (dds_entity *e, const dds_qos_t *qos, boo
 | 
			
		|||
  {
 | 
			
		||||
    struct reader *rd;
 | 
			
		||||
    thread_state_awake (lookup_thread_state (), &e->m_domain->gv);
 | 
			
		||||
    if ((rd = ephash_lookup_reader_guid (e->m_domain->gv.guid_hash, &e->m_guid)) != NULL)
 | 
			
		||||
    if ((rd = entidx_lookup_reader_guid (e->m_domain->gv.entity_index, &e->m_guid)) != NULL)
 | 
			
		||||
      update_reader_qos (rd, qos);
 | 
			
		||||
    thread_state_asleep (lookup_thread_state ());
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -512,7 +513,7 @@ void dds_reader_ddsi2direct (dds_entity_t entity, ddsi2direct_directread_cb_t cb
 | 
			
		|||
      pwrguid_next.entityid.u = (pwrguid_next.entityid.u & ~(uint32_t)0xff) | NN_ENTITYID_KIND_WRITER_NO_KEY;
 | 
			
		||||
    }
 | 
			
		||||
    ddsrt_mutex_unlock (&rd->e.lock);
 | 
			
		||||
    if ((pwr = ephash_lookup_proxy_writer_guid (dds_entity->m_domain->gv.guid_hash, &pwrguid)) != NULL)
 | 
			
		||||
    if ((pwr = entidx_lookup_proxy_writer_guid (dds_entity->m_domain->gv.entity_index, &pwrguid)) != NULL)
 | 
			
		||||
    {
 | 
			
		||||
      ddsrt_mutex_lock (&pwr->e.lock);
 | 
			
		||||
      pwr->ddsi2direct_cb = cb;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -39,6 +39,9 @@
 | 
			
		|||
#include "dds/ddsi/q_entity.h" /* proxy_writer_info */
 | 
			
		||||
#include "dds/ddsi/ddsi_serdata.h"
 | 
			
		||||
#include "dds/ddsi/ddsi_serdata_default.h"
 | 
			
		||||
#ifdef DDSI_INCLUDE_LIFESPAN
 | 
			
		||||
#include "dds/ddsi/ddsi_lifespan.h"
 | 
			
		||||
#endif
 | 
			
		||||
#include "dds/ddsi/sysdeps.h"
 | 
			
		||||
 | 
			
		||||
/* INSTANCE MANAGEMENT
 | 
			
		||||
| 
						 | 
				
			
			@ -122,9 +125,8 @@
 | 
			
		|||
   DDSI implementation, but still) will be done by also reseting "wr_iid"
 | 
			
		||||
   when an exclusive ownership writer lowers its strength.
 | 
			
		||||
 | 
			
		||||
   Lifespan, time base filter and deadline, are based on the instance
 | 
			
		||||
   timestamp ("tstamp").  This time stamp needs to be changed to either source
 | 
			
		||||
   or reception timestamp, depending on the ordering chosen.
 | 
			
		||||
   Lifespan is based on the reception timestamp, and the monotonic time is
 | 
			
		||||
   used for sample expiry if this QoS is set to something else than infinite.
 | 
			
		||||
 | 
			
		||||
   READ CONDITIONS
 | 
			
		||||
   ===============
 | 
			
		||||
| 
						 | 
				
			
			@ -244,6 +246,10 @@ struct rhc_sample {
 | 
			
		|||
  bool isread;                 /* READ or NOT_READ sample state */
 | 
			
		||||
  uint32_t disposed_gen;       /* snapshot of instance counter at time of insertion */
 | 
			
		||||
  uint32_t no_writers_gen;     /* __/ */
 | 
			
		||||
#ifdef DDSI_INCLUDE_LIFESPAN
 | 
			
		||||
  struct lifespan_fhnode lifespan;  /* fibheap node for lifespan */
 | 
			
		||||
  struct rhc_instance *inst;   /* reference to rhc instance */
 | 
			
		||||
#endif
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct rhc_instance {
 | 
			
		||||
| 
						 | 
				
			
			@ -289,15 +295,15 @@ struct dds_rhc_default {
 | 
			
		|||
  int32_t max_samples;   /* FIXME: probably better as uint32_t with MAX_UINT32 for unlimited */
 | 
			
		||||
  int32_t max_samples_per_instance; /* FIXME: probably better as uint32_t with MAX_UINT32 for unlimited */
 | 
			
		||||
 | 
			
		||||
  uint32_t n_instances;              /* # instances, including empty [NOT USED] */
 | 
			
		||||
  uint32_t n_instances;              /* # instances, including empty */
 | 
			
		||||
  uint32_t n_nonempty_instances;     /* # non-empty instances */
 | 
			
		||||
  uint32_t n_not_alive_disposed;     /* # disposed, non-empty instances [NOT USED] */
 | 
			
		||||
  uint32_t n_not_alive_no_writers;   /* # not-alive-no-writers, non-empty instances [NOT USED] */
 | 
			
		||||
  uint32_t n_new;                    /* # new, non-empty instances [NOT USED] */
 | 
			
		||||
  uint32_t n_not_alive_disposed;     /* # disposed, non-empty instances */
 | 
			
		||||
  uint32_t n_not_alive_no_writers;   /* # not-alive-no-writers, non-empty instances */
 | 
			
		||||
  uint32_t n_new;                    /* # new, non-empty instances */
 | 
			
		||||
  uint32_t n_vsamples;               /* # "valid" samples over all instances */
 | 
			
		||||
  uint32_t n_vread;                  /* # read "valid" samples over all instances [NOT USED] */
 | 
			
		||||
  uint32_t n_invsamples;             /* # invalid samples over all instances [NOT USED] */
 | 
			
		||||
  uint32_t n_invread;                /* # read invalid samples over all instances [NOT USED] */
 | 
			
		||||
  uint32_t n_vread;                  /* # read "valid" samples over all instances */
 | 
			
		||||
  uint32_t n_invsamples;             /* # invalid samples over all instances */
 | 
			
		||||
  uint32_t n_invread;                /* # read invalid samples over all instances */
 | 
			
		||||
 | 
			
		||||
  bool by_source_ordering;           /* true if BY_SOURCE, false if BY_RECEPTION */
 | 
			
		||||
  bool exclusive_ownership;          /* true if EXCLUSIVE, false if SHARED */
 | 
			
		||||
| 
						 | 
				
			
			@ -316,6 +322,9 @@ struct dds_rhc_default {
 | 
			
		|||
  uint32_t nqconds;                  /* Number of associated query conditions */
 | 
			
		||||
  dds_querycond_mask_t qconds_samplest;  /* Mask of associated query conditions that check the sample state */
 | 
			
		||||
  void *qcond_eval_samplebuf;        /* Temporary storage for evaluating query conditions, NULL if no qconds */
 | 
			
		||||
#ifdef DDSI_INCLUDE_LIFESPAN
 | 
			
		||||
  struct lifespan_adm lifespan;      /* Lifespan administration */
 | 
			
		||||
#endif
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct trigger_info_cmn {
 | 
			
		||||
| 
						 | 
				
			
			@ -460,6 +469,11 @@ static void topicless_to_clean_invsample (const struct ddsi_sertopic *topic, con
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
static unsigned qmask_of_inst (const struct rhc_instance *inst);
 | 
			
		||||
static void free_sample (struct dds_rhc_default *rhc, struct rhc_instance *inst, struct rhc_sample *s);
 | 
			
		||||
static void get_trigger_info_cmn (struct trigger_info_cmn *info, struct rhc_instance *inst);
 | 
			
		||||
static void get_trigger_info_pre (struct trigger_info_pre *info, struct rhc_instance *inst);
 | 
			
		||||
static void init_trigger_info_qcond (struct trigger_info_qcond *qc);
 | 
			
		||||
static void drop_instance_noupdate_no_writers (struct dds_rhc_default *rhc, struct rhc_instance *inst);
 | 
			
		||||
static bool update_conditions_locked (struct dds_rhc_default *rhc, bool called_from_insert, const struct trigger_info_pre *pre, const struct trigger_info_post *post, const struct trigger_info_qcond *trig_qc, const struct rhc_instance *inst, struct dds_entity *triggers[], size_t *ntriggers);
 | 
			
		||||
#ifndef NDEBUG
 | 
			
		||||
static int rhc_check_counts_locked (struct dds_rhc_default *rhc, bool check_conds, bool check_qcmask);
 | 
			
		||||
| 
						 | 
				
			
			@ -531,6 +545,83 @@ static void remove_inst_from_nonempty_list (struct dds_rhc_default *rhc, struct
 | 
			
		|||
  rhc->n_nonempty_instances--;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef DDSI_INCLUDE_LIFESPAN
 | 
			
		||||
static void drop_expired_samples (struct dds_rhc_default *rhc, struct rhc_sample *sample)
 | 
			
		||||
{
 | 
			
		||||
  struct rhc_instance *inst = sample->inst;
 | 
			
		||||
  struct trigger_info_pre pre;
 | 
			
		||||
  struct trigger_info_post post;
 | 
			
		||||
  struct trigger_info_qcond trig_qc;
 | 
			
		||||
  size_t ntriggers = SIZE_MAX;
 | 
			
		||||
 | 
			
		||||
  assert (!inst_is_empty (inst));
 | 
			
		||||
 | 
			
		||||
  TRACE ("rhc_default %p drop_exp(iid %"PRIx64" wriid %"PRIx64" exp %"PRId64" %s",
 | 
			
		||||
    rhc, inst->iid, sample->wr_iid, sample->lifespan.t_expire.v, sample->isread ? "read" : "notread");
 | 
			
		||||
 | 
			
		||||
  get_trigger_info_pre (&pre, inst);
 | 
			
		||||
  init_trigger_info_qcond (&trig_qc);
 | 
			
		||||
 | 
			
		||||
  /* Find prev sample: in case of history depth of 1 this is the sample itself,
 | 
			
		||||
    * (which is inst->latest). In case of larger history depth the most likely sample
 | 
			
		||||
    * to be expired is the oldest, in which case inst->latest is the previous
 | 
			
		||||
    * sample and inst->latest->next points to sample (circular list). We can
 | 
			
		||||
    * assume that 'sample' is in the list, so a check to avoid infinite loop is not
 | 
			
		||||
    * required here. */
 | 
			
		||||
  struct rhc_sample *psample = inst->latest;
 | 
			
		||||
  while (psample->next != sample)
 | 
			
		||||
    psample = psample->next;
 | 
			
		||||
 | 
			
		||||
  rhc->n_vsamples--;
 | 
			
		||||
  if (sample->isread)
 | 
			
		||||
  {
 | 
			
		||||
    inst->nvread--;
 | 
			
		||||
    rhc->n_vread--;
 | 
			
		||||
    trig_qc.dec_sample_read = true;
 | 
			
		||||
  }
 | 
			
		||||
  if (--inst->nvsamples > 0)
 | 
			
		||||
  {
 | 
			
		||||
    if (inst->latest == sample)
 | 
			
		||||
      inst->latest = psample;
 | 
			
		||||
    psample->next = sample->next;
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
    inst->latest = NULL;
 | 
			
		||||
  }
 | 
			
		||||
  trig_qc.dec_conds_sample = sample->conds;
 | 
			
		||||
  free_sample (rhc, inst, sample);
 | 
			
		||||
  get_trigger_info_cmn (&post.c, inst);
 | 
			
		||||
  update_conditions_locked (rhc, false, &pre, &post, &trig_qc, inst, NULL, &ntriggers);
 | 
			
		||||
  if (inst_is_empty (inst))
 | 
			
		||||
  {
 | 
			
		||||
    remove_inst_from_nonempty_list (rhc, inst);
 | 
			
		||||
    if (inst->isdisposed)
 | 
			
		||||
      rhc->n_not_alive_disposed--;
 | 
			
		||||
    if (inst->wrcount == 0)
 | 
			
		||||
    {
 | 
			
		||||
      TRACE ("; iid %"PRIx64" #0,empty,drop", inst->iid);
 | 
			
		||||
      if (!inst->isdisposed)
 | 
			
		||||
        rhc->n_not_alive_no_writers--;
 | 
			
		||||
      drop_instance_noupdate_no_writers (rhc, inst);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  TRACE (")\n");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
nn_mtime_t dds_rhc_default_sample_expired_cb(void *hc, nn_mtime_t tnow)
 | 
			
		||||
{
 | 
			
		||||
  struct dds_rhc_default *rhc = hc;
 | 
			
		||||
  struct rhc_sample *sample;
 | 
			
		||||
  nn_mtime_t tnext;
 | 
			
		||||
  ddsrt_mutex_lock (&rhc->lock);
 | 
			
		||||
  while ((tnext = lifespan_next_expired_locked (&rhc->lifespan, tnow, (void **)&sample)).v == 0)
 | 
			
		||||
    drop_expired_samples (rhc, sample);
 | 
			
		||||
  ddsrt_mutex_unlock (&rhc->lock);
 | 
			
		||||
  return tnext;
 | 
			
		||||
}
 | 
			
		||||
#endif /* DDSI_INCLUDE_LIFESPAN */
 | 
			
		||||
 | 
			
		||||
struct dds_rhc *dds_rhc_default_new_xchecks (dds_reader *reader, struct q_globals *gv, const struct ddsi_sertopic *topic, bool xchecks)
 | 
			
		||||
{
 | 
			
		||||
  struct dds_rhc_default *rhc = ddsrt_malloc (sizeof (*rhc));
 | 
			
		||||
| 
						 | 
				
			
			@ -546,6 +637,10 @@ struct dds_rhc *dds_rhc_default_new_xchecks (dds_reader *reader, struct q_global
 | 
			
		|||
  rhc->gv = gv;
 | 
			
		||||
  rhc->xchecks = xchecks;
 | 
			
		||||
 | 
			
		||||
#ifdef DDSI_INCLUDE_LIFESPAN
 | 
			
		||||
  lifespan_init (gv, &rhc->lifespan, offsetof(struct dds_rhc_default, lifespan), offsetof(struct rhc_sample, lifespan), dds_rhc_default_sample_expired_cb);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  return &rhc->common;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -601,9 +696,15 @@ static struct rhc_sample *alloc_sample (struct rhc_instance *inst)
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void free_sample (struct rhc_instance *inst, struct rhc_sample *s)
 | 
			
		||||
static void free_sample (struct dds_rhc_default *rhc, struct rhc_instance *inst, struct rhc_sample *s)
 | 
			
		||||
{
 | 
			
		||||
#ifndef DDSI_INCLUDE_LIFESPAN
 | 
			
		||||
  DDSRT_UNUSED_ARG (rhc);
 | 
			
		||||
#endif
 | 
			
		||||
  ddsi_serdata_unref (s->sample);
 | 
			
		||||
#ifdef DDSI_INCLUDE_LIFESPAN
 | 
			
		||||
  lifespan_unregister_sample_locked (&rhc->lifespan, &s->lifespan);
 | 
			
		||||
#endif
 | 
			
		||||
  if (s == &inst->a_sample)
 | 
			
		||||
  {
 | 
			
		||||
    assert (!inst->a_sample_free);
 | 
			
		||||
| 
						 | 
				
			
			@ -665,11 +766,12 @@ static void free_instance_rhc_free (struct rhc_instance *inst, struct dds_rhc_de
 | 
			
		|||
  struct rhc_sample *s = inst->latest;
 | 
			
		||||
  const bool was_empty = inst_is_empty (inst);
 | 
			
		||||
  struct trigger_info_qcond dummy_trig_qc;
 | 
			
		||||
 | 
			
		||||
  if (s)
 | 
			
		||||
  {
 | 
			
		||||
    do {
 | 
			
		||||
      struct rhc_sample * const s1 = s->next;
 | 
			
		||||
      free_sample (inst, s);
 | 
			
		||||
      free_sample (rhc, inst, s);
 | 
			
		||||
      s = s1;
 | 
			
		||||
    } while (s != inst->latest);
 | 
			
		||||
    rhc->n_vsamples -= inst->nvsamples;
 | 
			
		||||
| 
						 | 
				
			
			@ -682,11 +784,10 @@ static void free_instance_rhc_free (struct rhc_instance *inst, struct dds_rhc_de
 | 
			
		|||
#endif
 | 
			
		||||
  inst_clear_invsample_if_exists (rhc, inst, &dummy_trig_qc);
 | 
			
		||||
  if (!was_empty)
 | 
			
		||||
  {
 | 
			
		||||
    remove_inst_from_nonempty_list (rhc, inst);
 | 
			
		||||
  }
 | 
			
		||||
  ddsi_tkmap_instance_unref (rhc->tkmap, inst->tk);
 | 
			
		||||
  ddsrt_free (inst);
 | 
			
		||||
  if (inst->isnew)
 | 
			
		||||
    rhc->n_new--;
 | 
			
		||||
  free_empty_instance(inst, rhc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static uint32_t dds_rhc_default_lock_samples (struct dds_rhc_default *rhc)
 | 
			
		||||
| 
						 | 
				
			
			@ -708,7 +809,10 @@ static void free_instance_rhc_free_wrap (void *vnode, void *varg)
 | 
			
		|||
 | 
			
		||||
static void dds_rhc_default_free (struct dds_rhc_default *rhc)
 | 
			
		||||
{
 | 
			
		||||
  assert (rhc_check_counts_locked (rhc, true, true));
 | 
			
		||||
#ifdef DDSI_INCLUDE_LIFESPAN
 | 
			
		||||
  dds_rhc_default_sample_expired_cb (rhc, NN_MTIME_NEVER);
 | 
			
		||||
  lifespan_fini (&rhc->lifespan);
 | 
			
		||||
#endif
 | 
			
		||||
  ddsrt_hh_enum (rhc->instances, free_instance_rhc_free_wrap, rhc);
 | 
			
		||||
  assert (rhc->nonempty_instances == NULL);
 | 
			
		||||
  ddsrt_hh_free (rhc->instances);
 | 
			
		||||
| 
						 | 
				
			
			@ -789,6 +893,10 @@ static bool add_sample (struct dds_rhc_default *rhc, struct rhc_instance *inst,
 | 
			
		|||
    assert (trig_qc->dec_conds_sample == 0);
 | 
			
		||||
    ddsi_serdata_unref (s->sample);
 | 
			
		||||
 | 
			
		||||
#ifdef DDSI_INCLUDE_LIFESPAN
 | 
			
		||||
    lifespan_unregister_sample_locked (&rhc->lifespan, &s->lifespan);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    trig_qc->dec_sample_read = s->isread;
 | 
			
		||||
    trig_qc->dec_conds_sample = s->conds;
 | 
			
		||||
    if (s->isread)
 | 
			
		||||
| 
						 | 
				
			
			@ -843,6 +951,11 @@ static bool add_sample (struct dds_rhc_default *rhc, struct rhc_instance *inst,
 | 
			
		|||
  s->isread = false;
 | 
			
		||||
  s->disposed_gen = inst->disposed_gen;
 | 
			
		||||
  s->no_writers_gen = inst->no_writers_gen;
 | 
			
		||||
#ifdef DDSI_INCLUDE_LIFESPAN
 | 
			
		||||
  s->inst = inst;
 | 
			
		||||
  s->lifespan.t_expire = wrinfo->lifespan_exp;
 | 
			
		||||
  lifespan_register_sample_locked (&rhc->lifespan, &s->lifespan);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  s->conds = 0;
 | 
			
		||||
  if (rhc->nqconds != 0)
 | 
			
		||||
| 
						 | 
				
			
			@ -939,6 +1052,8 @@ static void drop_instance_noupdate_no_writers (struct dds_rhc_default *rhc, stru
 | 
			
		|||
  assert (inst_is_empty (inst));
 | 
			
		||||
 | 
			
		||||
  rhc->n_instances--;
 | 
			
		||||
  if (inst->isnew)
 | 
			
		||||
    rhc->n_new--;
 | 
			
		||||
 | 
			
		||||
  ret = ddsrt_hh_remove (rhc->instances, inst);
 | 
			
		||||
  assert (ret);
 | 
			
		||||
| 
						 | 
				
			
			@ -1065,7 +1180,6 @@ static void account_for_empty_to_nonempty_transition (struct dds_rhc_default *rh
 | 
			
		|||
{
 | 
			
		||||
  assert (inst_nsamples (inst) == 1);
 | 
			
		||||
  add_inst_to_nonempty_list (rhc, inst);
 | 
			
		||||
  rhc->n_new += inst->isnew;
 | 
			
		||||
  if (inst->isdisposed)
 | 
			
		||||
    rhc->n_not_alive_disposed++;
 | 
			
		||||
  else if (inst->wrcount == 0)
 | 
			
		||||
| 
						 | 
				
			
			@ -1294,6 +1408,7 @@ static rhc_store_result_t rhc_store_new_instance (struct rhc_instance **out_inst
 | 
			
		|||
  assert (ret);
 | 
			
		||||
  (void) ret;
 | 
			
		||||
  rhc->n_instances++;
 | 
			
		||||
  rhc->n_new++;
 | 
			
		||||
  get_trigger_info_cmn (&post->c, inst);
 | 
			
		||||
 | 
			
		||||
  *out_inst = inst;
 | 
			
		||||
| 
						 | 
				
			
			@ -1486,16 +1601,10 @@ static bool dds_rhc_default_store (struct dds_rhc_default * __restrict rhc, cons
 | 
			
		|||
      if (inst->latest || inst_became_disposed)
 | 
			
		||||
      {
 | 
			
		||||
        if (was_empty)
 | 
			
		||||
        {
 | 
			
		||||
          /* general function is slightly slower than a specialised
 | 
			
		||||
             one, but perhaps it is wiser to use the general one */
 | 
			
		||||
          account_for_empty_to_nonempty_transition (rhc, inst);
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
          rhc->n_not_alive_disposed += (uint32_t)(inst->isdisposed - old_isdisposed);
 | 
			
		||||
          rhc->n_new += (uint32_t)(inst->isnew - old_isnew);
 | 
			
		||||
        }
 | 
			
		||||
        rhc->n_new += (uint32_t)(inst->isnew - old_isnew);
 | 
			
		||||
      }
 | 
			
		||||
      else
 | 
			
		||||
      {
 | 
			
		||||
| 
						 | 
				
			
			@ -2032,7 +2141,7 @@ static int dds_rhc_take_w_qminv (struct dds_rhc_default *rhc, bool lock, void **
 | 
			
		|||
                  inst->latest = NULL;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                free_sample (inst, sample);
 | 
			
		||||
                free_sample (rhc, inst, sample);
 | 
			
		||||
 | 
			
		||||
                if (++n == max_samples)
 | 
			
		||||
                {
 | 
			
		||||
| 
						 | 
				
			
			@ -2179,7 +2288,7 @@ static int dds_rhc_takecdr_w_qminv (struct dds_rhc_default *rhc, bool lock, stru
 | 
			
		|||
                else
 | 
			
		||||
                  inst->latest = NULL;
 | 
			
		||||
 | 
			
		||||
                free_sample (inst, sample);
 | 
			
		||||
                free_sample (rhc, inst, sample);
 | 
			
		||||
 | 
			
		||||
                if (++n == max_samples)
 | 
			
		||||
                {
 | 
			
		||||
| 
						 | 
				
			
			@ -2442,7 +2551,11 @@ static bool update_conditions_locked (struct dds_rhc_default *rhc, bool called_f
 | 
			
		|||
         trig_qc->dec_conds_invsample, trig_qc->dec_conds_sample, trig_qc->inc_conds_invsample, trig_qc->inc_conds_sample);
 | 
			
		||||
 | 
			
		||||
  assert (rhc->n_nonempty_instances >= rhc->n_not_alive_disposed + rhc->n_not_alive_no_writers);
 | 
			
		||||
#ifndef DDSI_INCLUDE_LIFESPAN
 | 
			
		||||
  /* If lifespan is disabled, samples cannot expire and therefore
 | 
			
		||||
     empty instances cannot be in the 'new' state. */
 | 
			
		||||
  assert (rhc->n_nonempty_instances >= rhc->n_new);
 | 
			
		||||
#endif
 | 
			
		||||
  assert (rhc->n_vsamples >= rhc->n_vread);
 | 
			
		||||
 | 
			
		||||
  iter = rhc->conds;
 | 
			
		||||
| 
						 | 
				
			
			@ -2687,6 +2800,8 @@ static int rhc_check_counts_locked (struct dds_rhc_default *rhc, bool check_cond
 | 
			
		|||
    bool a_sample_free = true;
 | 
			
		||||
 | 
			
		||||
    n_instances++;
 | 
			
		||||
    if (inst->isnew)
 | 
			
		||||
      n_new++;
 | 
			
		||||
    if (inst_is_empty (inst))
 | 
			
		||||
      continue;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2695,8 +2810,6 @@ static int rhc_check_counts_locked (struct dds_rhc_default *rhc, bool check_cond
 | 
			
		|||
      n_not_alive_disposed++;
 | 
			
		||||
    else if (inst->wrcount == 0)
 | 
			
		||||
      n_not_alive_no_writers++;
 | 
			
		||||
    if (inst->isnew)
 | 
			
		||||
      n_new++;
 | 
			
		||||
 | 
			
		||||
    if (inst->latest)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -2790,9 +2903,7 @@ static int rhc_check_counts_locked (struct dds_rhc_default *rhc, bool check_cond
 | 
			
		|||
  if (check_conds)
 | 
			
		||||
  {
 | 
			
		||||
    for (i = 0, rciter = rhc->conds; i < ncheck; i++, rciter = rciter->m_next)
 | 
			
		||||
    {
 | 
			
		||||
      assert (cond_match_count[i] == ddsrt_atomic_ld32 (&rciter->m_entity.m_status.m_trigger));
 | 
			
		||||
    }
 | 
			
		||||
   }
 | 
			
		||||
 | 
			
		||||
  if (rhc->n_nonempty_instances == 0)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,6 +24,7 @@
 | 
			
		|||
#include "dds__serdata_builtintopic.h"
 | 
			
		||||
#include "dds/ddsi/ddsi_tkmap.h"
 | 
			
		||||
#include "dds/ddsi/q_entity.h"
 | 
			
		||||
#include "dds/ddsi/ddsi_entity_index.h"
 | 
			
		||||
 | 
			
		||||
static const uint64_t unihashconsts[] = {
 | 
			
		||||
  UINT64_C (16292676669999574021),
 | 
			
		||||
| 
						 | 
				
			
			@ -131,7 +132,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 ddsi_guid_t *) keyhash->value);
 | 
			
		||||
  struct entity_common *entity = entidx_lookup_guid_untyped (tp->gv->entity_index, (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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1288,9 +1288,12 @@ static void dds_stream_extract_key_from_key_prim_op (dds_istream_t * __restrict
 | 
			
		|||
#if DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN
 | 
			
		||||
static void dds_stream_swap_copy (void * __restrict vdst, const void * __restrict vsrc, uint32_t size, uint32_t num)
 | 
			
		||||
{
 | 
			
		||||
  assert (size == 2 || size == 4 || size == 8);
 | 
			
		||||
  assert (size == 1 || size == 2 || size == 4 || size == 8);
 | 
			
		||||
  switch (size)
 | 
			
		||||
  {
 | 
			
		||||
    case 1:
 | 
			
		||||
      memcpy (vdst, vsrc, num);
 | 
			
		||||
      break;
 | 
			
		||||
    case 2: {
 | 
			
		||||
      const uint16_t *src = vsrc;
 | 
			
		||||
      uint16_t *dst = vdst;
 | 
			
		||||
| 
						 | 
				
			
			@ -1342,7 +1345,7 @@ static void dds_stream_extract_keyBE_from_key_prim_op (dds_istream_t * __restric
 | 
			
		|||
      void const * const src = is->m_buffer + is->m_index;
 | 
			
		||||
      void * const dst = os->x.m_buffer + os->x.m_index;
 | 
			
		||||
#if DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN
 | 
			
		||||
      dds_stream_swap_copy (dst, src, num, align);
 | 
			
		||||
      dds_stream_swap_copy (dst, src, align, num);
 | 
			
		||||
#else
 | 
			
		||||
      memcpy (dst, src, num * align);
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -1722,7 +1725,7 @@ static bool prtf_simple_array (char * __restrict *buf, size_t * __restrict bufsi
 | 
			
		|||
      abort ();
 | 
			
		||||
      break;
 | 
			
		||||
  }
 | 
			
		||||
  return cont;
 | 
			
		||||
  return prtf (buf, bufsize, "}");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -25,6 +25,7 @@
 | 
			
		|||
#include "dds__get_status.h"
 | 
			
		||||
#include "dds__qos.h"
 | 
			
		||||
#include "dds/ddsi/q_entity.h"
 | 
			
		||||
#include "dds/ddsi/ddsi_entity_index.h"
 | 
			
		||||
#include "dds/ddsi/q_thread.h"
 | 
			
		||||
#include "dds/ddsi/ddsi_sertopic.h"
 | 
			
		||||
#include "dds/ddsi/q_ddsi_discovery.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -437,7 +438,7 @@ dds_entity_t dds_create_topic_arbitrary (dds_entity_t participant, struct ddsi_s
 | 
			
		|||
 | 
			
		||||
  /* Publish Topic */
 | 
			
		||||
  thread_state_awake (lookup_thread_state (), &par->m_entity.m_domain->gv);
 | 
			
		||||
  ddsi_pp = ephash_lookup_participant_guid (par->m_entity.m_domain->gv.guid_hash, &par->m_entity.m_guid);
 | 
			
		||||
  ddsi_pp = entidx_lookup_participant_guid (par->m_entity.m_domain->gv.entity_index, &par->m_entity.m_guid);
 | 
			
		||||
  assert (ddsi_pp);
 | 
			
		||||
  if (sedp_plist)
 | 
			
		||||
  {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,25 +12,28 @@
 | 
			
		|||
#include <assert.h>
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#include "dds/ddsrt/heap.h"
 | 
			
		||||
#include "dds/ddsrt/sync.h"
 | 
			
		||||
#include "dds/ddsrt/misc.h"
 | 
			
		||||
#include "dds/ddsrt/avl.h"
 | 
			
		||||
#include "dds/ddsrt/fibheap.h"
 | 
			
		||||
#include "dds/ddsrt/hopscotch.h"
 | 
			
		||||
#include "dds/ddsi/ddsi_serdata.h"
 | 
			
		||||
#ifdef DDSI_INCLUDE_LIFESPAN
 | 
			
		||||
#include "dds/ddsi/ddsi_lifespan.h"
 | 
			
		||||
#endif
 | 
			
		||||
#include "dds/ddsi/q_unused.h"
 | 
			
		||||
#include "dds/ddsi/q_config.h"
 | 
			
		||||
#include "dds__whc.h"
 | 
			
		||||
#include "dds/ddsi/ddsi_tkmap.h"
 | 
			
		||||
 | 
			
		||||
#include "dds/ddsrt/avl.h"
 | 
			
		||||
#include "dds/ddsrt/hopscotch.h"
 | 
			
		||||
#include "dds/ddsi/q_time.h"
 | 
			
		||||
#include "dds/ddsi/q_rtps.h"
 | 
			
		||||
#include "dds/ddsi/q_freelist.h"
 | 
			
		||||
#include "dds/ddsi/q_globals.h"
 | 
			
		||||
#include "dds__whc.h"
 | 
			
		||||
 | 
			
		||||
#define USE_EHH 0
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct whc_node {
 | 
			
		||||
  struct whc_node *next_seq; /* next in this interval */
 | 
			
		||||
  struct whc_node *prev_seq; /* prev in this interval */
 | 
			
		||||
| 
						 | 
				
			
			@ -44,6 +47,9 @@ struct whc_node {
 | 
			
		|||
  unsigned borrowed: 1; /* at most one can borrow it at any time */
 | 
			
		||||
  nn_mtime_t last_rexmit_ts;
 | 
			
		||||
  uint32_t rexmit_count;
 | 
			
		||||
#ifdef DDSI_INCLUDE_LIFESPAN
 | 
			
		||||
  struct lifespan_fhnode lifespan; /* fibheap node for lifespan */
 | 
			
		||||
#endif
 | 
			
		||||
  struct ddsi_serdata *serdata;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -95,6 +101,9 @@ struct whc_impl {
 | 
			
		|||
#endif
 | 
			
		||||
  struct ddsrt_hh *idx_hash;
 | 
			
		||||
  ddsrt_avl_tree_t seq;
 | 
			
		||||
#ifdef DDSI_INCLUDE_LIFESPAN
 | 
			
		||||
  struct lifespan_adm lifespan; /* Lifespan administration */
 | 
			
		||||
#endif
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct whc_sample_iter_impl {
 | 
			
		||||
| 
						 | 
				
			
			@ -128,7 +137,7 @@ static uint32_t whc_default_remove_acked_messages_full (struct whc_impl *whc, se
 | 
			
		|||
static uint32_t whc_default_remove_acked_messages (struct whc *whc, seqno_t max_drop_seq, struct whc_state *whcst, struct whc_node **deferred_free_list);
 | 
			
		||||
static void whc_default_free_deferred_free_list (struct whc *whc, struct whc_node *deferred_free_list);
 | 
			
		||||
static void whc_default_get_state (const struct whc *whc, struct whc_state *st);
 | 
			
		||||
static int whc_default_insert (struct whc *whc, seqno_t max_drop_seq, seqno_t seq, struct nn_plist *plist, struct ddsi_serdata *serdata, struct ddsi_tkmap_instance *tk);
 | 
			
		||||
static int whc_default_insert (struct whc *whc, seqno_t max_drop_seq, seqno_t seq, nn_mtime_t exp, struct nn_plist *plist, struct ddsi_serdata *serdata, struct ddsi_tkmap_instance *tk);
 | 
			
		||||
static seqno_t whc_default_next_seq (const struct whc *whc, seqno_t seq);
 | 
			
		||||
static bool whc_default_borrow_sample (const struct whc *whc, seqno_t seq, struct whc_borrowed_sample *sample);
 | 
			
		||||
static bool whc_default_borrow_sample_key (const struct whc *whc, const struct ddsi_serdata *serdata_key, struct whc_borrowed_sample *sample);
 | 
			
		||||
| 
						 | 
				
			
			@ -349,6 +358,21 @@ static struct whc_node *whc_findkey (const struct whc_impl *whc, const struct dd
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef DDSI_INCLUDE_LIFESPAN
 | 
			
		||||
static nn_mtime_t whc_sample_expired_cb(void *hc, nn_mtime_t tnow)
 | 
			
		||||
{
 | 
			
		||||
  struct whc_impl *whc = hc;
 | 
			
		||||
  void *sample;
 | 
			
		||||
  nn_mtime_t tnext;
 | 
			
		||||
  ddsrt_mutex_lock (&whc->lock);
 | 
			
		||||
  while ((tnext = lifespan_next_expired_locked (&whc->lifespan, tnow, &sample)).v == 0)
 | 
			
		||||
    whc_delete_one (whc, sample);
 | 
			
		||||
  whc->maxseq_node = whc_findmax_procedurally (whc);
 | 
			
		||||
  ddsrt_mutex_unlock (&whc->lock);
 | 
			
		||||
  return tnext;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
struct whc *whc_new (struct q_globals *gv, int is_transient_local, uint32_t hdepth, uint32_t tldepth)
 | 
			
		||||
{
 | 
			
		||||
  size_t sample_overhead = 80; /* INFO_TS, DATA (estimate), inline QoS */
 | 
			
		||||
| 
						 | 
				
			
			@ -384,6 +408,10 @@ struct whc *whc_new (struct q_globals *gv, int is_transient_local, uint32_t hdep
 | 
			
		|||
  else
 | 
			
		||||
    whc->idx_hash = NULL;
 | 
			
		||||
 | 
			
		||||
#ifdef DDSI_INCLUDE_LIFESPAN
 | 
			
		||||
  lifespan_init (gv, &whc->lifespan, offsetof(struct whc_impl, lifespan), offsetof(struct whc_node, lifespan), whc_sample_expired_cb);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  /* seq interval tree: always has an "open" node */
 | 
			
		||||
  ddsrt_avl_init (&whc_seq_treedef, &whc->seq);
 | 
			
		||||
  intv = ddsrt_malloc (sizeof (*intv));
 | 
			
		||||
| 
						 | 
				
			
			@ -417,6 +445,11 @@ void whc_default_free (struct whc *whc_generic)
 | 
			
		|||
  struct whc_impl * const whc = (struct whc_impl *)whc_generic;
 | 
			
		||||
  check_whc (whc);
 | 
			
		||||
 | 
			
		||||
#ifdef DDSI_INCLUDE_LIFESPAN
 | 
			
		||||
  whc_sample_expired_cb (whc, NN_MTIME_NEVER);
 | 
			
		||||
  lifespan_fini (&whc->lifespan);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  if (whc->idx_hash)
 | 
			
		||||
  {
 | 
			
		||||
    struct ddsrt_hh_iter it;
 | 
			
		||||
| 
						 | 
				
			
			@ -686,6 +719,10 @@ static void whc_delete_one_intv (struct whc_impl *whc, struct whc_intvnode **p_i
 | 
			
		|||
    whcn->unacked = 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
#ifdef DDSI_INCLUDE_LIFESPAN
 | 
			
		||||
  lifespan_unregister_sample_locked (&whc->lifespan, &whcn->lifespan);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  /* Take it out of seqhash; deleting it from the list ordered on
 | 
			
		||||
   sequence numbers is left to the caller (it has to be done unconditionally,
 | 
			
		||||
   but remove_acked_messages defers it until the end or a skipped node). */
 | 
			
		||||
| 
						 | 
				
			
			@ -869,6 +906,9 @@ static uint32_t whc_default_remove_acked_messages_noidx (struct whc_impl *whc, s
 | 
			
		|||
  whc->unacked_bytes -= (size_t) (whcn->total_bytes - (*deferred_free_list)->total_bytes + (*deferred_free_list)->size);
 | 
			
		||||
  for (whcn = *deferred_free_list; whcn; whcn = whcn->next_seq)
 | 
			
		||||
  {
 | 
			
		||||
#ifdef DDSI_INCLUDE_LIFESPAN
 | 
			
		||||
    lifespan_unregister_sample_locked (&whc->lifespan, &whcn->lifespan);
 | 
			
		||||
#endif
 | 
			
		||||
    remove_whcn_from_hash (whc, whcn);
 | 
			
		||||
    assert (whcn->unacked);
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -1035,10 +1075,16 @@ static uint32_t whc_default_remove_acked_messages (struct whc *whc_generic, seqn
 | 
			
		|||
  return cnt;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct whc_node *whc_default_insert_seq (struct whc_impl *whc, seqno_t max_drop_seq, seqno_t seq, struct nn_plist *plist, struct ddsi_serdata *serdata)
 | 
			
		||||
static struct whc_node *whc_default_insert_seq (struct whc_impl *whc, seqno_t max_drop_seq, seqno_t seq, nn_mtime_t exp, struct nn_plist *plist, struct ddsi_serdata *serdata)
 | 
			
		||||
{
 | 
			
		||||
  struct whc_node *newn = NULL;
 | 
			
		||||
 | 
			
		||||
#ifndef DDSI_INCLUDE_LIFESPAN
 | 
			
		||||
  /* FIXME: the 'exp' arg is used for lifespan, refactor this parameter to a struct 'writer info'
 | 
			
		||||
    that contains both lifespan and deadline info of the writer */
 | 
			
		||||
  DDSRT_UNUSED_ARG (exp);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  if ((newn = nn_freelist_pop (&whc_node_freelist)) == NULL)
 | 
			
		||||
    newn = ddsrt_malloc (sizeof (*newn));
 | 
			
		||||
  newn->seq = seq;
 | 
			
		||||
| 
						 | 
				
			
			@ -1062,6 +1108,10 @@ static struct whc_node *whc_default_insert_seq (struct whc_impl *whc, seqno_t ma
 | 
			
		|||
  if (newn->unacked)
 | 
			
		||||
    whc->unacked_bytes += newn->size;
 | 
			
		||||
 | 
			
		||||
#ifdef DDSI_INCLUDE_LIFESPAN
 | 
			
		||||
  newn->lifespan.t_expire = exp;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  insert_whcn_in_hash (whc, newn);
 | 
			
		||||
 | 
			
		||||
  if (whc->open_intv->first == NULL)
 | 
			
		||||
| 
						 | 
				
			
			@ -1093,10 +1143,13 @@ static struct whc_node *whc_default_insert_seq (struct whc_impl *whc, seqno_t ma
 | 
			
		|||
  }
 | 
			
		||||
 | 
			
		||||
  whc->seq_size++;
 | 
			
		||||
#ifdef DDSI_INCLUDE_LIFESPAN
 | 
			
		||||
  lifespan_register_sample_locked (&whc->lifespan, &newn->lifespan);
 | 
			
		||||
#endif
 | 
			
		||||
  return newn;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int whc_default_insert (struct whc *whc_generic, seqno_t max_drop_seq, seqno_t seq, struct nn_plist *plist, struct ddsi_serdata *serdata, struct ddsi_tkmap_instance *tk)
 | 
			
		||||
static int whc_default_insert (struct whc *whc_generic, seqno_t max_drop_seq, seqno_t seq, nn_mtime_t exp, struct nn_plist *plist, struct ddsi_serdata *serdata, struct ddsi_tkmap_instance *tk)
 | 
			
		||||
{
 | 
			
		||||
  struct whc_impl * const whc = (struct whc_impl *)whc_generic;
 | 
			
		||||
  struct whc_node *newn = NULL;
 | 
			
		||||
| 
						 | 
				
			
			@ -1106,6 +1159,9 @@ static int whc_default_insert (struct whc *whc_generic, seqno_t max_drop_seq, se
 | 
			
		|||
    char pad[sizeof (struct whc_idxnode) + sizeof (struct whc_node *)];
 | 
			
		||||
  } template;
 | 
			
		||||
 | 
			
		||||
  /* FIXME: the 'exp' arg is used for lifespan, refactor this parameter to a struct 'writer info'
 | 
			
		||||
    that contains both lifespan als deadline info of the writer */
 | 
			
		||||
 | 
			
		||||
  ddsrt_mutex_lock (&whc->lock);
 | 
			
		||||
  check_whc (whc);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1113,8 +1169,8 @@ static int whc_default_insert (struct whc *whc_generic, seqno_t max_drop_seq, se
 | 
			
		|||
  {
 | 
			
		||||
    struct whc_state whcst;
 | 
			
		||||
    get_state_locked (whc, &whcst);
 | 
			
		||||
    TRACE ("whc_default_insert(%p max_drop_seq %"PRId64" seq %"PRId64" plist %p serdata %p:%"PRIx32")\n",
 | 
			
		||||
           (void *) whc, max_drop_seq, seq, (void *) plist, (void *) serdata, serdata->hash);
 | 
			
		||||
    TRACE ("whc_default_insert(%p max_drop_seq %"PRId64" seq %"PRId64" exp %"PRId64" plist %p serdata %p:%"PRIx32")\n",
 | 
			
		||||
           (void *) whc, max_drop_seq, seq, exp.v, (void *) plist, (void *) serdata, serdata->hash);
 | 
			
		||||
    TRACE ("  whc: [%"PRId64",%"PRId64"] max_drop_seq %"PRId64" h %"PRIu32" tl %"PRIu32"\n",
 | 
			
		||||
           whcst.min_seq, whcst.max_seq, whc->max_drop_seq, whc->hdepth, whc->tldepth);
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -1128,7 +1184,7 @@ static int whc_default_insert (struct whc *whc_generic, seqno_t max_drop_seq, se
 | 
			
		|||
  assert (whc->seq_size == 0 || seq > whc->maxseq_node->seq);
 | 
			
		||||
 | 
			
		||||
  /* Always insert in seq admin */
 | 
			
		||||
  newn = whc_default_insert_seq (whc, max_drop_seq, seq, plist, serdata);
 | 
			
		||||
  newn = whc_default_insert_seq (whc, max_drop_seq, seq, exp, plist, serdata);
 | 
			
		||||
 | 
			
		||||
  TRACE ("  whcn %p:", (void*)newn);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,7 +17,7 @@
 | 
			
		|||
#include "dds/ddsi/ddsi_serdata.h"
 | 
			
		||||
#include "dds/ddsi/q_unused.h"
 | 
			
		||||
#include "dds/ddsi/q_config.h"
 | 
			
		||||
#include "dds/ddsi/q_ephash.h"
 | 
			
		||||
#include "dds/ddsi/ddsi_entity_index.h"
 | 
			
		||||
#include "dds/ddsi/q_entity.h"
 | 
			
		||||
#include "dds/ddsi/q_globals.h"
 | 
			
		||||
#include "dds/ddsi/ddsi_tkmap.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -28,7 +28,7 @@
 | 
			
		|||
struct bwhc {
 | 
			
		||||
  struct whc common;
 | 
			
		||||
  enum ddsi_sertopic_builtintopic_type type;
 | 
			
		||||
  const struct ephash *guid_hash;
 | 
			
		||||
  const struct entity_index *entidx;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum bwhc_iter_state {
 | 
			
		||||
| 
						 | 
				
			
			@ -42,7 +42,7 @@ struct bwhc_iter {
 | 
			
		|||
  struct whc_sample_iter_base c;
 | 
			
		||||
  enum bwhc_iter_state st;
 | 
			
		||||
  bool have_sample;
 | 
			
		||||
  struct ephash_enum it;
 | 
			
		||||
  struct entidx_enum it;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* check that our definition of whc_sample_iter fits in the type that callers allocate */
 | 
			
		||||
| 
						 | 
				
			
			@ -92,11 +92,11 @@ static bool bwhc_sample_iter_borrow_next (struct whc_sample_iter *opaque_it, str
 | 
			
		|||
        case DSBT_READER:      kind = EK_READER; break;
 | 
			
		||||
      }
 | 
			
		||||
      assert (whc->type == DSBT_PARTICIPANT || kind != EK_PARTICIPANT);
 | 
			
		||||
      ephash_enum_init (&it->it, whc->guid_hash, kind);
 | 
			
		||||
      entidx_enum_init (&it->it, whc->entidx, kind);
 | 
			
		||||
      it->st = BIS_LOCAL;
 | 
			
		||||
      /* FALLS THROUGH */
 | 
			
		||||
    case BIS_LOCAL:
 | 
			
		||||
      while ((entity = ephash_enum_next (&it->it)) != NULL)
 | 
			
		||||
      while ((entity = entidx_enum_next (&it->it)) != NULL)
 | 
			
		||||
        if (is_visible (entity))
 | 
			
		||||
          break;
 | 
			
		||||
      if (entity) {
 | 
			
		||||
| 
						 | 
				
			
			@ -104,7 +104,7 @@ static bool bwhc_sample_iter_borrow_next (struct whc_sample_iter *opaque_it, str
 | 
			
		|||
        it->have_sample = true;
 | 
			
		||||
        return true;
 | 
			
		||||
      } else {
 | 
			
		||||
        ephash_enum_fini (&it->it);
 | 
			
		||||
        entidx_enum_fini (&it->it);
 | 
			
		||||
        it->st = BIS_INIT_PROXY;
 | 
			
		||||
      }
 | 
			
		||||
      /* FALLS THROUGH */
 | 
			
		||||
| 
						 | 
				
			
			@ -115,11 +115,11 @@ static bool bwhc_sample_iter_borrow_next (struct whc_sample_iter *opaque_it, str
 | 
			
		|||
        case DSBT_READER:      kind = EK_PROXY_READER; break;
 | 
			
		||||
      }
 | 
			
		||||
      assert (kind != EK_PARTICIPANT);
 | 
			
		||||
      ephash_enum_init (&it->it, whc->guid_hash, kind);
 | 
			
		||||
      entidx_enum_init (&it->it, whc->entidx, kind);
 | 
			
		||||
      it->st = BIS_PROXY;
 | 
			
		||||
      /* FALLS THROUGH */
 | 
			
		||||
    case BIS_PROXY:
 | 
			
		||||
      while ((entity = ephash_enum_next (&it->it)) != NULL)
 | 
			
		||||
      while ((entity = entidx_enum_next (&it->it)) != NULL)
 | 
			
		||||
        if (is_visible (entity))
 | 
			
		||||
          break;
 | 
			
		||||
      if (entity) {
 | 
			
		||||
| 
						 | 
				
			
			@ -127,7 +127,7 @@ static bool bwhc_sample_iter_borrow_next (struct whc_sample_iter *opaque_it, str
 | 
			
		|||
        it->have_sample = true;
 | 
			
		||||
        return true;
 | 
			
		||||
      } else {
 | 
			
		||||
        ephash_enum_fini (&it->it);
 | 
			
		||||
        entidx_enum_fini (&it->it);
 | 
			
		||||
        return false;
 | 
			
		||||
      }
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -143,11 +143,12 @@ static void bwhc_get_state (const struct whc *whc, struct whc_state *st)
 | 
			
		|||
  st->unacked_bytes = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int bwhc_insert (struct whc *whc, seqno_t max_drop_seq, seqno_t seq, struct nn_plist *plist, struct ddsi_serdata *serdata, struct ddsi_tkmap_instance *tk)
 | 
			
		||||
static int bwhc_insert (struct whc *whc, seqno_t max_drop_seq, seqno_t seq, nn_mtime_t exp, struct nn_plist *plist, struct ddsi_serdata *serdata, struct ddsi_tkmap_instance *tk)
 | 
			
		||||
{
 | 
			
		||||
  (void)whc;
 | 
			
		||||
  (void)max_drop_seq;
 | 
			
		||||
  (void)seq;
 | 
			
		||||
  (void)exp;
 | 
			
		||||
  (void)serdata;
 | 
			
		||||
  (void)tk;
 | 
			
		||||
  if (plist)
 | 
			
		||||
| 
						 | 
				
			
			@ -192,11 +193,11 @@ static const struct whc_ops bwhc_ops = {
 | 
			
		|||
  .free = bwhc_free
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct whc *builtintopic_whc_new (enum ddsi_sertopic_builtintopic_type type, const struct ephash *guid_hash)
 | 
			
		||||
struct whc *builtintopic_whc_new (enum ddsi_sertopic_builtintopic_type type, const struct entity_index *entidx)
 | 
			
		||||
{
 | 
			
		||||
  struct bwhc *whc = ddsrt_malloc (sizeof (*whc));
 | 
			
		||||
  whc->common.ops = &bwhc_ops;
 | 
			
		||||
  whc->type = type;
 | 
			
		||||
  whc->guid_hash = guid_hash;
 | 
			
		||||
  whc->entidx = entidx;
 | 
			
		||||
  return (struct whc *) whc;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,7 +20,7 @@
 | 
			
		|||
#include "dds/ddsi/ddsi_serdata.h"
 | 
			
		||||
#include "dds__stream.h"
 | 
			
		||||
#include "dds/ddsi/q_transmit.h"
 | 
			
		||||
#include "dds/ddsi/q_ephash.h"
 | 
			
		||||
#include "dds/ddsi/ddsi_entity_index.h"
 | 
			
		||||
#include "dds/ddsi/q_config.h"
 | 
			
		||||
#include "dds/ddsi/q_entity.h"
 | 
			
		||||
#include "dds/ddsi/q_radmin.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -99,7 +99,7 @@ static dds_return_t deliver_locally (struct writer *wr, struct ddsi_serdata *pay
 | 
			
		|||
    {
 | 
			
		||||
      dds_duration_t max_block_ms = wr->xqos->reliability.max_blocking_time;
 | 
			
		||||
      struct ddsi_writer_info pwr_info;
 | 
			
		||||
      ddsi_make_writer_info (&pwr_info, &wr->e, wr->xqos);
 | 
			
		||||
      ddsi_make_writer_info (&pwr_info, &wr->e, wr->xqos, payload->statusinfo);
 | 
			
		||||
      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)
 | 
			
		||||
| 
						 | 
				
			
			@ -121,15 +121,15 @@ static dds_return_t deliver_locally (struct writer *wr, struct ddsi_serdata *pay
 | 
			
		|||
    ddsrt_avl_iter_t it;
 | 
			
		||||
    struct pwr_rd_match *m;
 | 
			
		||||
    struct ddsi_writer_info wrinfo;
 | 
			
		||||
    const struct ephash *gh = wr->e.gv->guid_hash;
 | 
			
		||||
    const struct entity_index *gh = wr->e.gv->entity_index;
 | 
			
		||||
    dds_duration_t max_block_ms = wr->xqos->reliability.max_blocking_time;
 | 
			
		||||
    ddsrt_mutex_unlock (&wr->rdary.rdary_lock);
 | 
			
		||||
    ddsi_make_writer_info (&wrinfo, &wr->e, wr->xqos);
 | 
			
		||||
    ddsi_make_writer_info (&wrinfo, &wr->e, wr->xqos, payload->statusinfo);
 | 
			
		||||
    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))
 | 
			
		||||
    {
 | 
			
		||||
      struct reader *rd;
 | 
			
		||||
      if ((rd = ephash_lookup_reader_guid (gh, &m->rd_guid)) != NULL)
 | 
			
		||||
      if ((rd = entidx_lookup_reader_guid (gh, &m->rd_guid)) != NULL)
 | 
			
		||||
      {
 | 
			
		||||
        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. */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,6 +19,7 @@
 | 
			
		|||
#include "dds/ddsi/q_entity.h"
 | 
			
		||||
#include "dds/ddsi/q_thread.h"
 | 
			
		||||
#include "dds/ddsi/q_xmsg.h"
 | 
			
		||||
#include "dds/ddsi/ddsi_entity_index.h"
 | 
			
		||||
#include "dds__writer.h"
 | 
			
		||||
#include "dds__listener.h"
 | 
			
		||||
#include "dds__init.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -217,14 +218,28 @@ static dds_return_t dds_writer_delete (dds_entity *e)
 | 
			
		|||
  return DDS_RETCODE_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static dds_return_t validate_writer_qos (const dds_qos_t *wqos)
 | 
			
		||||
{
 | 
			
		||||
#ifndef DDSI_INCLUDE_LIFESPAN
 | 
			
		||||
  if (wqos != NULL && (wqos->present & QP_LIFESPAN) && wqos->lifespan.duration != DDS_INFINITY)
 | 
			
		||||
    return DDS_RETCODE_BAD_PARAMETER;
 | 
			
		||||
#else
 | 
			
		||||
  DDSRT_UNUSED_ARG (wqos);
 | 
			
		||||
#endif
 | 
			
		||||
  return DDS_RETCODE_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static dds_return_t dds_writer_qos_set (dds_entity *e, const dds_qos_t *qos, bool enabled)
 | 
			
		||||
{
 | 
			
		||||
  /* note: e->m_qos is still the old one to allow for failure here */
 | 
			
		||||
  dds_return_t ret;
 | 
			
		||||
  if ((ret = validate_writer_qos(qos)) != DDS_RETCODE_OK)
 | 
			
		||||
    return ret;
 | 
			
		||||
  if (enabled)
 | 
			
		||||
  {
 | 
			
		||||
    struct writer *wr;
 | 
			
		||||
    thread_state_awake (lookup_thread_state (), &e->m_domain->gv);
 | 
			
		||||
    if ((wr = ephash_lookup_writer_guid (e->m_domain->gv.guid_hash, &e->m_guid)) != NULL)
 | 
			
		||||
    if ((wr = entidx_lookup_writer_guid (e->m_domain->gv.entity_index, &e->m_guid)) != NULL)
 | 
			
		||||
      update_writer_qos (wr, qos);
 | 
			
		||||
    thread_state_asleep (lookup_thread_state ());
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -319,7 +334,8 @@ dds_entity_t dds_create_writer (dds_entity_t participant_or_publisher, dds_entit
 | 
			
		|||
    nn_xqos_mergein_missing (wqos, tp->m_entity.m_qos, ~(uint64_t)0);
 | 
			
		||||
  nn_xqos_mergein_missing (wqos, &pub->m_entity.m_domain->gv.default_xqos_wr, ~(uint64_t)0);
 | 
			
		||||
 | 
			
		||||
  if ((rc = nn_xqos_valid (&pub->m_entity.m_domain->gv.logconfig, wqos)) < 0)
 | 
			
		||||
  if ((rc = nn_xqos_valid (&pub->m_entity.m_domain->gv.logconfig, wqos)) < 0 ||
 | 
			
		||||
      (rc = validate_writer_qos(wqos)) != DDS_RETCODE_OK)
 | 
			
		||||
  {
 | 
			
		||||
    dds_delete_qos(wqos);
 | 
			
		||||
    goto err_bad_qos;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,6 +14,7 @@ include(CUnit)
 | 
			
		|||
idlc_generate(RoundTrip RoundTrip.idl)
 | 
			
		||||
idlc_generate(Space Space.idl)
 | 
			
		||||
idlc_generate(TypesArrayKey TypesArrayKey.idl)
 | 
			
		||||
idlc_generate(WriteTypes WriteTypes.idl)
 | 
			
		||||
 | 
			
		||||
set(ddsc_test_sources
 | 
			
		||||
    "basic.c"
 | 
			
		||||
| 
						 | 
				
			
			@ -51,15 +52,20 @@ set(ddsc_test_sources
 | 
			
		|||
    "waitset.c"
 | 
			
		||||
    "waitset_torture.c"
 | 
			
		||||
    "write.c"
 | 
			
		||||
    "write_various_types.c"
 | 
			
		||||
    "writer.c")
 | 
			
		||||
 | 
			
		||||
if(ENABLE_LIFESPAN)
 | 
			
		||||
  list(APPEND ddsc_test_sources "lifespan.c")
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
add_cunit_executable(cunit_ddsc ${ddsc_test_sources})
 | 
			
		||||
target_include_directories(
 | 
			
		||||
  cunit_ddsc PRIVATE
 | 
			
		||||
  "$<BUILD_INTERFACE:${CMAKE_BINARY_DIR}/src/include/>"
 | 
			
		||||
  "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../../ddsc/src>"
 | 
			
		||||
  "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../../ddsi/include>")
 | 
			
		||||
target_link_libraries(cunit_ddsc PRIVATE RoundTrip Space TypesArrayKey ddsc)
 | 
			
		||||
target_link_libraries(cunit_ddsc PRIVATE RoundTrip Space TypesArrayKey WriteTypes ddsc)
 | 
			
		||||
 | 
			
		||||
# Setup environment for config-tests
 | 
			
		||||
get_test_property(CUnit_ddsc_config_simple_udp ENVIRONMENT CUnit_ddsc_config_simple_udp_env)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										25
									
								
								src/core/ddsc/tests/WriteTypes.idl
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/core/ddsc/tests/WriteTypes.idl
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,25 @@
 | 
			
		|||
module WriteTypes {
 | 
			
		||||
  struct a {
 | 
			
		||||
    octet k[3];
 | 
			
		||||
    unsigned long long ll;
 | 
			
		||||
  };
 | 
			
		||||
#pragma keylist a k
 | 
			
		||||
 | 
			
		||||
  struct b {
 | 
			
		||||
    unsigned short k[3];
 | 
			
		||||
    unsigned long long ll;
 | 
			
		||||
  };
 | 
			
		||||
#pragma keylist b k
 | 
			
		||||
 | 
			
		||||
  struct c {
 | 
			
		||||
    unsigned long k[3];
 | 
			
		||||
    unsigned long long ll;
 | 
			
		||||
  };
 | 
			
		||||
#pragma keylist c k
 | 
			
		||||
  
 | 
			
		||||
  struct d {
 | 
			
		||||
    unsigned long long k[3];
 | 
			
		||||
    unsigned long long ll;
 | 
			
		||||
  };
 | 
			
		||||
#pragma keylist d k
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										164
									
								
								src/core/ddsc/tests/lifespan.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										164
									
								
								src/core/ddsc/tests/lifespan.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,164 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
 | 
			
		||||
 *
 | 
			
		||||
 * This program and the accompanying materials are made available under the
 | 
			
		||||
 * terms of the Eclipse Public License v. 2.0 which is available at
 | 
			
		||||
 * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
 | 
			
		||||
 * v. 1.0 which is available at
 | 
			
		||||
 * http://www.eclipse.org/org/documents/edl-v10.php.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
 | 
			
		||||
#include "dds/dds.h"
 | 
			
		||||
#include "CUnit/Theory.h"
 | 
			
		||||
#include "Space.h"
 | 
			
		||||
 | 
			
		||||
#include "dds/ddsrt/process.h"
 | 
			
		||||
#include "dds/ddsrt/threads.h"
 | 
			
		||||
#include "dds/ddsi/ddsi_entity_index.h"
 | 
			
		||||
#include "dds/ddsi/q_entity.h"
 | 
			
		||||
#include "dds/ddsi/q_whc.h"
 | 
			
		||||
#include "dds__entity.h"
 | 
			
		||||
 | 
			
		||||
static dds_entity_t g_participant = 0;
 | 
			
		||||
static dds_entity_t g_subscriber  = 0;
 | 
			
		||||
static dds_entity_t g_publisher   = 0;
 | 
			
		||||
static dds_entity_t g_topic       = 0;
 | 
			
		||||
static dds_entity_t g_reader      = 0;
 | 
			
		||||
static dds_entity_t g_writer      = 0;
 | 
			
		||||
static dds_entity_t g_waitset     = 0;
 | 
			
		||||
static dds_entity_t g_rcond       = 0;
 | 
			
		||||
static dds_entity_t g_qcond       = 0;
 | 
			
		||||
 | 
			
		||||
static char*
 | 
			
		||||
create_topic_name(const char *prefix, char *name, size_t size)
 | 
			
		||||
{
 | 
			
		||||
    /* Get semi random g_topic name. */
 | 
			
		||||
    ddsrt_pid_t pid = ddsrt_getpid();
 | 
			
		||||
    ddsrt_tid_t tid = ddsrt_gettid();
 | 
			
		||||
    (void) snprintf(name, size, "%s_pid%"PRIdPID"_tid%"PRIdTID"", prefix, pid, tid);
 | 
			
		||||
    return name;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void lifespan_init(void)
 | 
			
		||||
{
 | 
			
		||||
  dds_attach_t triggered;
 | 
			
		||||
  dds_return_t ret;
 | 
			
		||||
  char name[100];
 | 
			
		||||
  dds_qos_t *qos;
 | 
			
		||||
 | 
			
		||||
  qos = dds_create_qos();
 | 
			
		||||
  CU_ASSERT_PTR_NOT_NULL_FATAL(qos);
 | 
			
		||||
 | 
			
		||||
  g_participant = dds_create_participant(DDS_DOMAIN_DEFAULT, NULL, NULL);
 | 
			
		||||
  CU_ASSERT_FATAL(g_participant > 0);
 | 
			
		||||
 | 
			
		||||
  g_subscriber = dds_create_subscriber(g_participant, NULL, NULL);
 | 
			
		||||
  CU_ASSERT_FATAL(g_subscriber > 0);
 | 
			
		||||
 | 
			
		||||
  g_publisher = dds_create_publisher(g_participant, NULL, NULL);
 | 
			
		||||
  CU_ASSERT_FATAL(g_publisher > 0);
 | 
			
		||||
 | 
			
		||||
  g_waitset = dds_create_waitset(g_participant);
 | 
			
		||||
  CU_ASSERT_FATAL(g_waitset > 0);
 | 
			
		||||
 | 
			
		||||
  g_topic = dds_create_topic(g_participant, &Space_Type1_desc, create_topic_name("ddsc_qos_lifespan_test", name, sizeof name), NULL, NULL);
 | 
			
		||||
  CU_ASSERT_FATAL(g_topic > 0);
 | 
			
		||||
 | 
			
		||||
  dds_qset_history(qos, DDS_HISTORY_KEEP_ALL, DDS_LENGTH_UNLIMITED);
 | 
			
		||||
  dds_qset_durability(qos, DDS_DURABILITY_TRANSIENT_LOCAL);
 | 
			
		||||
  dds_qset_reliability(qos, DDS_RELIABILITY_RELIABLE, DDS_INFINITY);
 | 
			
		||||
  g_writer = dds_create_writer(g_publisher, g_topic, qos, NULL);
 | 
			
		||||
  CU_ASSERT_FATAL(g_writer > 0);
 | 
			
		||||
  g_reader = dds_create_reader(g_subscriber, g_topic, qos, NULL);
 | 
			
		||||
  CU_ASSERT_FATAL(g_reader > 0);
 | 
			
		||||
 | 
			
		||||
  /* Sync g_reader to g_writer. */
 | 
			
		||||
  ret = dds_set_status_mask(g_reader, DDS_SUBSCRIPTION_MATCHED_STATUS);
 | 
			
		||||
  CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
 | 
			
		||||
  ret = dds_waitset_attach(g_waitset, g_reader, g_reader);
 | 
			
		||||
  CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
 | 
			
		||||
  ret = dds_waitset_wait(g_waitset, &triggered, 1, DDS_SECS(1));
 | 
			
		||||
  CU_ASSERT_EQUAL_FATAL(ret, 1);
 | 
			
		||||
  CU_ASSERT_EQUAL_FATAL(g_reader, (dds_entity_t)(intptr_t)triggered);
 | 
			
		||||
  ret = dds_waitset_detach(g_waitset, g_reader);
 | 
			
		||||
  CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
 | 
			
		||||
 | 
			
		||||
  /* Sync g_writer to g_reader. */
 | 
			
		||||
  ret = dds_set_status_mask(g_writer, DDS_PUBLICATION_MATCHED_STATUS);
 | 
			
		||||
  CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
 | 
			
		||||
  ret = dds_waitset_attach(g_waitset, g_writer, g_writer);
 | 
			
		||||
  CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
 | 
			
		||||
  ret = dds_waitset_wait(g_waitset, &triggered, 1, DDS_SECS(1));
 | 
			
		||||
  CU_ASSERT_EQUAL_FATAL(ret, 1);
 | 
			
		||||
  CU_ASSERT_EQUAL_FATAL(g_writer, (dds_entity_t)(intptr_t)triggered);
 | 
			
		||||
  ret = dds_waitset_detach(g_waitset, g_writer);
 | 
			
		||||
  CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
 | 
			
		||||
 | 
			
		||||
  dds_delete_qos(qos);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void lifespan_fini(void)
 | 
			
		||||
{
 | 
			
		||||
  dds_delete(g_rcond);
 | 
			
		||||
  dds_delete(g_qcond);
 | 
			
		||||
  dds_delete(g_reader);
 | 
			
		||||
  dds_delete(g_writer);
 | 
			
		||||
  dds_delete(g_subscriber);
 | 
			
		||||
  dds_delete(g_publisher);
 | 
			
		||||
  dds_delete(g_waitset);
 | 
			
		||||
  dds_delete(g_topic);
 | 
			
		||||
  dds_delete(g_participant);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void check_whc_state(dds_entity_t writer, seqno_t exp_min, seqno_t exp_max)
 | 
			
		||||
{
 | 
			
		||||
  struct dds_entity *wr_entity;
 | 
			
		||||
  struct writer *wr;
 | 
			
		||||
  struct whc_state whcst;
 | 
			
		||||
  CU_ASSERT_EQUAL_FATAL(dds_entity_pin(writer, &wr_entity), 0);
 | 
			
		||||
  thread_state_awake(lookup_thread_state(), &wr_entity->m_domain->gv);
 | 
			
		||||
  wr = entidx_lookup_writer_guid(wr_entity->m_domain->gv.entity_index, &wr_entity->m_guid);
 | 
			
		||||
  CU_ASSERT_FATAL(wr != NULL);
 | 
			
		||||
  assert(wr != NULL); /* for Clang's static analyzer */
 | 
			
		||||
  whc_get_state(wr->whc, &whcst);
 | 
			
		||||
  thread_state_asleep(lookup_thread_state());
 | 
			
		||||
  dds_entity_unpin(wr_entity);
 | 
			
		||||
 | 
			
		||||
  CU_ASSERT_EQUAL_FATAL (whcst.min_seq, exp_min);
 | 
			
		||||
  CU_ASSERT_EQUAL_FATAL (whcst.max_seq, exp_max);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
CU_Test(ddsc_lifespan, basic, .init=lifespan_init, .fini=lifespan_fini)
 | 
			
		||||
{
 | 
			
		||||
  Space_Type1 sample = { 0, 0, 0 };
 | 
			
		||||
  dds_return_t ret;
 | 
			
		||||
  dds_duration_t exp = DDS_MSECS(500);
 | 
			
		||||
  dds_qos_t *qos;
 | 
			
		||||
 | 
			
		||||
  qos = dds_create_qos();
 | 
			
		||||
  CU_ASSERT_PTR_NOT_NULL_FATAL(qos);
 | 
			
		||||
 | 
			
		||||
  /* Write with default qos: lifespan inifinite */
 | 
			
		||||
  ret = dds_write (g_writer, &sample);
 | 
			
		||||
  CU_ASSERT_EQUAL_FATAL (ret, DDS_RETCODE_OK);
 | 
			
		||||
  check_whc_state(g_writer, 1, 1);
 | 
			
		||||
 | 
			
		||||
  dds_sleepfor (2 * exp);
 | 
			
		||||
  check_whc_state(g_writer, 1, 1);
 | 
			
		||||
 | 
			
		||||
  dds_qset_lifespan(qos, exp);
 | 
			
		||||
  ret = dds_set_qos(g_writer, qos);
 | 
			
		||||
  CU_ASSERT_EQUAL_FATAL (ret, DDS_RETCODE_OK);
 | 
			
		||||
  ret = dds_write (g_writer, &sample);
 | 
			
		||||
  CU_ASSERT_EQUAL_FATAL (ret, DDS_RETCODE_OK);
 | 
			
		||||
  check_whc_state(g_writer, 2, 2);
 | 
			
		||||
 | 
			
		||||
  dds_sleepfor (2 * exp);
 | 
			
		||||
  check_whc_state(g_writer, -1, -1);
 | 
			
		||||
 | 
			
		||||
  dds_delete_qos(qos);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -20,6 +20,7 @@
 | 
			
		|||
#include "dds/version.h"
 | 
			
		||||
#include "dds__entity.h"
 | 
			
		||||
#include "dds/ddsi/q_entity.h"
 | 
			
		||||
#include "dds/ddsi/ddsi_entity_index.h"
 | 
			
		||||
#include "dds/ddsrt/cdtors.h"
 | 
			
		||||
#include "dds/ddsrt/misc.h"
 | 
			
		||||
#include "dds/ddsrt/process.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -97,7 +98,7 @@ static seqno_t get_pmd_seqno(dds_entity_t participant)
 | 
			
		|||
  struct writer *wr;
 | 
			
		||||
  CU_ASSERT_EQUAL_FATAL(dds_entity_pin(participant, &pp_entity), 0);
 | 
			
		||||
  thread_state_awake(lookup_thread_state(), &pp_entity->m_domain->gv);
 | 
			
		||||
  pp = ephash_lookup_participant_guid(pp_entity->m_domain->gv.guid_hash, &pp_entity->m_guid);
 | 
			
		||||
  pp = entidx_lookup_participant_guid(pp_entity->m_domain->gv.entity_index, &pp_entity->m_guid);
 | 
			
		||||
  wr = get_builtin_writer(pp, NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER);
 | 
			
		||||
  CU_ASSERT_FATAL(wr != NULL);
 | 
			
		||||
  assert(wr != NULL); /* for Clang's static analyzer */
 | 
			
		||||
| 
						 | 
				
			
			@ -117,7 +118,7 @@ static dds_duration_t get_pmd_interval(dds_entity_t participant)
 | 
			
		|||
  struct participant *pp;
 | 
			
		||||
  CU_ASSERT_EQUAL_FATAL(dds_entity_pin(participant, &pp_entity), 0);
 | 
			
		||||
  thread_state_awake(lookup_thread_state(), &pp_entity->m_domain->gv);
 | 
			
		||||
  pp = ephash_lookup_participant_guid(pp_entity->m_domain->gv.guid_hash, &pp_entity->m_guid);
 | 
			
		||||
  pp = entidx_lookup_participant_guid(pp_entity->m_domain->gv.entity_index, &pp_entity->m_guid);
 | 
			
		||||
  intv = pp_get_pmd_interval(pp);
 | 
			
		||||
  thread_state_asleep(lookup_thread_state());
 | 
			
		||||
  dds_entity_unpin(pp_entity);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										249
									
								
								src/core/ddsc/tests/write_various_types.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										249
									
								
								src/core/ddsc/tests/write_various_types.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,249 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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 "WriteTypes.h"
 | 
			
		||||
 | 
			
		||||
#include "dds/ddsrt/process.h"
 | 
			
		||||
#include "dds/ddsrt/threads.h"
 | 
			
		||||
#include "dds/ddsrt/environ.h"
 | 
			
		||||
 | 
			
		||||
#define DDS_DOMAINID_PUB 0
 | 
			
		||||
#define DDS_DOMAINID_SUB 1
 | 
			
		||||
#define DDS_CONFIG_NO_PORT_GAIN "${CYCLONEDDS_URI}${CYCLONEDDS_URI:+,}<Discovery><ExternalDomainId>0</ExternalDomainId></Discovery>"
 | 
			
		||||
#define DDS_CONFIG_NO_PORT_GAIN_LOG "${CYCLONEDDS_URI}${CYCLONEDDS_URI:+,}<Tracing><OutputFile>cyclonedds_writetypes_various.${CYCLONEDDS_DOMAIN_ID}.${CYCLONEDDS_PID}.log</OutputFile><Verbosity>finest</Verbosity></Tracing><Discovery><ExternalDomainId>0</ExternalDomainId></Discovery>"
 | 
			
		||||
 | 
			
		||||
static uint32_t g_topic_nr = 0;
 | 
			
		||||
static dds_entity_t g_pub_domain = 0;
 | 
			
		||||
static dds_entity_t g_pub_participant = 0;
 | 
			
		||||
static dds_entity_t g_pub_publisher = 0;
 | 
			
		||||
 | 
			
		||||
static dds_entity_t g_sub_domain = 0;
 | 
			
		||||
static dds_entity_t g_sub_participant = 0;
 | 
			
		||||
static dds_entity_t g_sub_subscriber = 0;
 | 
			
		||||
 | 
			
		||||
static char *create_topic_name (const char *prefix, uint32_t nr, char *name, size_t size)
 | 
			
		||||
{
 | 
			
		||||
  /* Get unique g_topic name. */
 | 
			
		||||
  ddsrt_pid_t pid = ddsrt_getpid ();
 | 
			
		||||
  ddsrt_tid_t tid = ddsrt_gettid ();
 | 
			
		||||
  (void) snprintf (name, size, "%s%d_pid%" PRIdPID "_tid%" PRIdTID "", prefix, nr, pid, tid);
 | 
			
		||||
  return name;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void writetypes_init(void)
 | 
			
		||||
{
 | 
			
		||||
  /* Domains for pub and sub use a different domain id, but the portgain setting
 | 
			
		||||
   * in configuration is 0, so that both domains will map to the same port number.
 | 
			
		||||
   * This allows to create two domains in a single test process. */
 | 
			
		||||
  char *conf_pub = ddsrt_expand_envvars (DDS_CONFIG_NO_PORT_GAIN, DDS_DOMAINID_PUB);
 | 
			
		||||
  char *conf_sub = ddsrt_expand_envvars (DDS_CONFIG_NO_PORT_GAIN, DDS_DOMAINID_SUB);
 | 
			
		||||
  g_pub_domain = dds_create_domain (DDS_DOMAINID_PUB, conf_pub);
 | 
			
		||||
  g_sub_domain = dds_create_domain (DDS_DOMAINID_SUB, conf_sub);
 | 
			
		||||
  dds_free (conf_pub);
 | 
			
		||||
  dds_free (conf_sub);
 | 
			
		||||
 | 
			
		||||
  g_pub_participant = dds_create_participant (DDS_DOMAINID_PUB, NULL, NULL);
 | 
			
		||||
  CU_ASSERT_FATAL (g_pub_participant > 0);
 | 
			
		||||
  g_sub_participant = dds_create_participant (DDS_DOMAINID_SUB, NULL, NULL);
 | 
			
		||||
  CU_ASSERT_FATAL (g_sub_participant > 0);
 | 
			
		||||
 | 
			
		||||
  g_pub_publisher = dds_create_publisher (g_pub_participant, NULL, NULL);
 | 
			
		||||
  CU_ASSERT_FATAL (g_pub_publisher > 0);
 | 
			
		||||
  g_sub_subscriber = dds_create_subscriber (g_sub_participant, NULL, NULL);
 | 
			
		||||
  CU_ASSERT_FATAL (g_sub_subscriber > 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void writetypes_fini (void)
 | 
			
		||||
{
 | 
			
		||||
  dds_delete (g_sub_subscriber);
 | 
			
		||||
  dds_delete (g_pub_publisher);
 | 
			
		||||
  dds_delete (g_sub_participant);
 | 
			
		||||
  dds_delete (g_pub_participant);
 | 
			
		||||
  dds_delete (g_sub_domain);
 | 
			
		||||
  dds_delete (g_pub_domain);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
typedef bool (*compare_fn_t) (const void *a, const void *b);
 | 
			
		||||
 | 
			
		||||
#define ABCD_CMP(typ_)                                                  \
 | 
			
		||||
  static bool typ_##_cmp (const void *va, const void *vb)               \
 | 
			
		||||
  {                                                                     \
 | 
			
		||||
    const struct WriteTypes_##typ_ *a = va;                             \
 | 
			
		||||
    const struct WriteTypes_##typ_ *b = vb;                             \
 | 
			
		||||
    return a->k[0] == b->k[0] && a->k[1] == b->k[1] && a->k[2] == b->k[2] && a->ll == b->ll; \
 | 
			
		||||
  }
 | 
			
		||||
ABCD_CMP (a)
 | 
			
		||||
ABCD_CMP (b)
 | 
			
		||||
ABCD_CMP (c)
 | 
			
		||||
ABCD_CMP (d)
 | 
			
		||||
#undef ABCD_CMP
 | 
			
		||||
 | 
			
		||||
struct sample {
 | 
			
		||||
  bool in_result;
 | 
			
		||||
  const void *data;
 | 
			
		||||
};
 | 
			
		||||
#define S(n) &(struct WriteTypes_##n)
 | 
			
		||||
static const struct sample a_samples[] = {
 | 
			
		||||
  { 1, S(a) { .k={1,2,3}, .ll = UINT64_C (0x1234567890abcdef) } },
 | 
			
		||||
  { 0, S(a) { .k={3,2,1}, .ll = UINT64_C (0) } },
 | 
			
		||||
  { 1, S(a) { .k={3,2,1}, .ll = UINT64_C (1) } },
 | 
			
		||||
};
 | 
			
		||||
static const struct sample b_samples[] = {
 | 
			
		||||
  { 1, S(b) { .k={1001,1002,1003}, .ll = UINT64_C (0x1234567890abcdef) } },
 | 
			
		||||
  { 0, S(b) { .k={1003,1002,1001}, .ll = UINT64_C (0) } },
 | 
			
		||||
  { 1, S(b) { .k={1003,1002,1001}, .ll = UINT64_C (1) } },
 | 
			
		||||
};
 | 
			
		||||
static const struct sample c_samples[] = {
 | 
			
		||||
  { 1, S(c) { .k={12340001,12340002,12340003}, .ll = UINT64_C (0x1234567890abcdef) } },
 | 
			
		||||
  { 0, S(c) { .k={12340003,12340002,12340001}, .ll = UINT64_C (0) } },
 | 
			
		||||
  { 1, S(c) { .k={12340003,12340002,12340001}, .ll = UINT64_C (1) } },
 | 
			
		||||
};
 | 
			
		||||
static const struct sample d_samples[] = {
 | 
			
		||||
  { 1, S(d) { .k={123400056780001,2,3}, .ll = UINT64_C (0x1234567890abcdef) } },
 | 
			
		||||
  { 0, S(d) { .k={123400056780003,2,1}, .ll = UINT64_C (0) } },
 | 
			
		||||
  { 1, S(d) { .k={123400056780003,2,1}, .ll = UINT64_C (1) } },
 | 
			
		||||
};
 | 
			
		||||
#undef S
 | 
			
		||||
 | 
			
		||||
#define T(n) &WriteTypes_##n##_desc
 | 
			
		||||
#define C(n) &n##_cmp
 | 
			
		||||
#define N(n) (sizeof (n##_samples) / sizeof (n##_samples[0]))
 | 
			
		||||
#define S(n) n##_samples
 | 
			
		||||
CU_TheoryDataPoints(ddsc_writetypes, various) = {
 | 
			
		||||
  CU_DataPoints(const dds_topic_descriptor_t *, T(a), T(b), T(c), T(d)),
 | 
			
		||||
  CU_DataPoints(compare_fn_t,                   C(a), C(b), C(c), C(d)),
 | 
			
		||||
  CU_DataPoints(size_t,                         N(a), N(b), N(c), N(d)),
 | 
			
		||||
  CU_DataPoints(const struct sample *,          S(a), S(b), S(c), S(d)),
 | 
			
		||||
};
 | 
			
		||||
#undef S
 | 
			
		||||
#undef N
 | 
			
		||||
#undef C
 | 
			
		||||
#undef T
 | 
			
		||||
 | 
			
		||||
#define MAX_SAMPLES 5
 | 
			
		||||
 | 
			
		||||
CU_Theory((const dds_topic_descriptor_t *desc, compare_fn_t cmp, size_t nsamples, const struct sample *samples), ddsc_writetypes, various, .init = writetypes_init, .fini = writetypes_fini, .timeout = 10)
 | 
			
		||||
{
 | 
			
		||||
  dds_entity_t pub_topic;
 | 
			
		||||
  dds_entity_t sub_topic;
 | 
			
		||||
  dds_entity_t reader;
 | 
			
		||||
  dds_entity_t writer;
 | 
			
		||||
  dds_qos_t *qos;
 | 
			
		||||
  dds_return_t rc;
 | 
			
		||||
  char name[100];
 | 
			
		||||
 | 
			
		||||
  /* nsamples < MAX_SAMPLES so there is room for an invalid sample if we need it */
 | 
			
		||||
  CU_ASSERT_FATAL (nsamples < MAX_SAMPLES);
 | 
			
		||||
 | 
			
		||||
  qos = dds_create_qos ();
 | 
			
		||||
  CU_ASSERT_FATAL (qos != NULL);
 | 
			
		||||
  dds_qset_reliability (qos, DDS_RELIABILITY_RELIABLE, DDS_SECS (1));
 | 
			
		||||
  dds_qset_writer_data_lifecycle (qos, false);
 | 
			
		||||
  create_topic_name ("ddsc_writetypes_various", g_topic_nr++, name, sizeof name);
 | 
			
		||||
  pub_topic = dds_create_topic (g_pub_participant, desc, name, qos, NULL);
 | 
			
		||||
  CU_ASSERT_FATAL (pub_topic > 0);
 | 
			
		||||
  sub_topic = dds_create_topic (g_sub_participant, desc, name, qos, NULL);
 | 
			
		||||
  CU_ASSERT_FATAL (sub_topic > 0);
 | 
			
		||||
  dds_delete_qos (qos);
 | 
			
		||||
 | 
			
		||||
  reader = dds_create_reader (g_sub_participant, sub_topic, NULL, NULL);
 | 
			
		||||
  CU_ASSERT_FATAL (reader > 0);
 | 
			
		||||
  writer = dds_create_writer (g_pub_participant, pub_topic, NULL, NULL);
 | 
			
		||||
  CU_ASSERT_FATAL (writer > 0);
 | 
			
		||||
 | 
			
		||||
  /* simple-minded polling until reader/writer have matched each other */
 | 
			
		||||
  while (1)
 | 
			
		||||
  {
 | 
			
		||||
    dds_publication_matched_status_t st;
 | 
			
		||||
    rc = dds_get_publication_matched_status (writer, &st);
 | 
			
		||||
    CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
 | 
			
		||||
    if (st.current_count > 0)
 | 
			
		||||
      break;
 | 
			
		||||
    dds_sleepfor (DDS_MSECS (1));
 | 
			
		||||
  }
 | 
			
		||||
  while (1)
 | 
			
		||||
  {
 | 
			
		||||
    dds_subscription_matched_status_t st;
 | 
			
		||||
    rc = dds_get_subscription_matched_status (reader, &st);
 | 
			
		||||
    CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
 | 
			
		||||
    if (st.current_count > 0)
 | 
			
		||||
      break;
 | 
			
		||||
    dds_sleepfor (DDS_MSECS (1));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /* write samples */
 | 
			
		||||
  for (size_t i = 0; i < nsamples; i++) {
 | 
			
		||||
    rc = dds_write (writer, samples[i].data);
 | 
			
		||||
    CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /* delete writer, wait until no matching writer: writer lingering should ensure the data
 | 
			
		||||
     has been delivered at that point */
 | 
			
		||||
  rc = dds_delete (writer);
 | 
			
		||||
  CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
 | 
			
		||||
  while (1)
 | 
			
		||||
  {
 | 
			
		||||
    dds_subscription_matched_status_t st;
 | 
			
		||||
    rc = dds_get_subscription_matched_status (reader, &st);
 | 
			
		||||
    CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
 | 
			
		||||
    if (st.current_count == 0)
 | 
			
		||||
      break;
 | 
			
		||||
    dds_sleepfor (DDS_MSECS (1));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /* instances are unordered; this is a woefully inefficient way of comparing the sets,
 | 
			
		||||
     but for the numbers of samples we do here, it really doesn't matter */
 | 
			
		||||
  dds_sample_info_t si[MAX_SAMPLES];
 | 
			
		||||
  void *xs[MAX_SAMPLES];
 | 
			
		||||
  xs[0] = NULL;
 | 
			
		||||
  int32_t n;
 | 
			
		||||
  n = dds_read (reader, xs, si, MAX_SAMPLES, MAX_SAMPLES);
 | 
			
		||||
  CU_ASSERT_FATAL (n > 0);
 | 
			
		||||
 | 
			
		||||
  size_t nvalid = 0;
 | 
			
		||||
  for (int32_t j = 0; j < n; j++)
 | 
			
		||||
  {
 | 
			
		||||
    if (si[j].valid_data)
 | 
			
		||||
      nvalid++;
 | 
			
		||||
  }
 | 
			
		||||
  for (size_t i = 0; i < nsamples; i++)
 | 
			
		||||
  {
 | 
			
		||||
    if (samples[i].in_result)
 | 
			
		||||
    {
 | 
			
		||||
      /* sample must be present, erase it by marking it invalid */
 | 
			
		||||
      int32_t j;
 | 
			
		||||
      for (j = 0; j < n; j++)
 | 
			
		||||
        if (si[j].valid_data && cmp (samples[i].data, xs[j]))
 | 
			
		||||
          break;
 | 
			
		||||
      CU_ASSERT (j < n);
 | 
			
		||||
      si[j].valid_data = 0;
 | 
			
		||||
      nvalid--;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  /* all valid samples must be accounted for */
 | 
			
		||||
  CU_ASSERT_FATAL (nvalid == 0);
 | 
			
		||||
 | 
			
		||||
  rc = dds_return_loan (reader, xs, n);
 | 
			
		||||
  CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
 | 
			
		||||
 | 
			
		||||
  /* cleanup */
 | 
			
		||||
  rc = dds_delete (reader);
 | 
			
		||||
  CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
 | 
			
		||||
  rc = dds_delete (sub_topic);
 | 
			
		||||
  CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
 | 
			
		||||
  rc = dds_delete (pub_topic);
 | 
			
		||||
  CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue