From 219cb6cf4fc01688f2b02013a7ccd14a08b2bf12 Mon Sep 17 00:00:00 2001 From: Dennis Potman Date: Wed, 18 Dec 2019 16:19:59 +0100 Subject: [PATCH] Refactored linked list administration in rhc so that it becomes reusable Signed-off-by: Dennis Potman --- src/core/ddsc/src/dds_rhc_default.c | 115 ++++++++++--------------- src/ddsrt/CMakeLists.txt | 20 ++--- src/ddsrt/include/dds/ddsrt/circlist.h | 43 +++++++++ src/ddsrt/src/circlist.c | 84 ++++++++++++++++++ 4 files changed, 182 insertions(+), 80 deletions(-) create mode 100644 src/ddsrt/include/dds/ddsrt/circlist.h create mode 100644 src/ddsrt/src/circlist.c diff --git a/src/core/ddsc/src/dds_rhc_default.c b/src/core/ddsc/src/dds_rhc_default.c index a3922cb..15bf67d 100644 --- a/src/core/ddsc/src/dds_rhc_default.c +++ b/src/core/ddsc/src/dds_rhc_default.c @@ -30,6 +30,7 @@ #include "dds/ddsi/ddsi_tkmap.h" #include "dds/ddsrt/hopscotch.h" #include "dds/ddsrt/avl.h" +#include "dds/ddsrt/circlist.h" #include "dds/ddsi/ddsi_rhc.h" #include "dds/ddsi/q_xqos.h" #include "dds/ddsi/q_unused.h" @@ -271,8 +272,7 @@ struct rhc_instance { int32_t strength; /* "current" ownership strength */ 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; + struct ddsrt_circlist_elem nonempty_list; /* links non-empty instances in arbitrary ordering */ struct ddsi_tkmap_instance *tk; /* backref into TK for unref'ing */ struct rhc_sample a_sample; /* pre-allocated storage for 1 sample */ }; @@ -286,7 +286,7 @@ typedef enum rhc_store_result { struct dds_rhc_default { struct dds_rhc common; struct ddsrt_hh *instances; - struct rhc_instance *nonempty_instances; /* circular, points to most recently added one, NULL if none */ + struct ddsrt_circlist nonempty_instances; /* circular, points to most recently added one, NULL if none */ struct lwregs registrations; /* should be a global one (with lock-free lookups) */ /* Instance/Sample maximums from resource limits QoS */ @@ -494,57 +494,33 @@ static int instance_iid_eq (const void *va, const void *vb) static void add_inst_to_nonempty_list (struct dds_rhc_default *rhc, struct rhc_instance *inst) { - if (rhc->nonempty_instances == NULL) - { - inst->next = inst->prev = inst; - } - else - { - struct rhc_instance * const hd = rhc->nonempty_instances; -#ifndef NDEBUG - { - const struct rhc_instance *x = hd; - do { assert (x != inst); x = x->next; } while (x != hd); - } -#endif - inst->next = hd->next; - inst->prev = hd; - hd->next = inst; - inst->next->prev = inst; - } - rhc->nonempty_instances = inst; + ddsrt_circlist_append (&rhc->nonempty_instances, &inst->nonempty_list); rhc->n_nonempty_instances++; } static void remove_inst_from_nonempty_list (struct dds_rhc_default *rhc, struct rhc_instance *inst) { assert (inst_is_empty (inst)); -#ifndef NDEBUG - { - const struct rhc_instance *x = rhc->nonempty_instances; - assert (x); - do { if (x == inst) break; x = x->next; } while (x != rhc->nonempty_instances); - assert (x == inst); - } -#endif - - if (inst->next == inst) - { - rhc->nonempty_instances = NULL; - } - else - { - struct rhc_instance * const inst_prev = inst->prev; - struct rhc_instance * const inst_next = inst->next; - inst_prev->next = inst_next; - inst_next->prev = inst_prev; - if (rhc->nonempty_instances == inst) - rhc->nonempty_instances = inst_prev; - } + ddsrt_circlist_remove (&rhc->nonempty_instances, &inst->nonempty_list); assert (rhc->n_nonempty_instances > 0); rhc->n_nonempty_instances--; } +static struct rhc_instance *oldest_nonempty_instance (const struct dds_rhc_default *rhc) +{ + return DDSRT_FROM_CIRCLIST (struct rhc_instance, nonempty_list, ddsrt_circlist_oldest (&rhc->nonempty_instances)); +} + +static struct rhc_instance *latest_nonempty_instance (const struct dds_rhc_default *rhc) +{ + return DDSRT_FROM_CIRCLIST (struct rhc_instance, nonempty_list, ddsrt_circlist_latest (&rhc->nonempty_instances)); +} + +static struct rhc_instance *next_nonempty_instance (const struct rhc_instance *inst) +{ + return DDSRT_FROM_CIRCLIST (struct rhc_instance, nonempty_list, inst->nonempty_list.next); +} + #ifdef DDSI_INCLUDE_LIFESPAN static void drop_expired_samples (struct dds_rhc_default *rhc, struct rhc_sample *sample) { @@ -631,6 +607,7 @@ struct dds_rhc *dds_rhc_default_new_xchecks (dds_reader *reader, struct q_global lwregs_init (&rhc->registrations); ddsrt_mutex_init (&rhc->lock); rhc->instances = ddsrt_hh_new (1, instance_iid_hash, instance_iid_eq); + ddsrt_circlist_init (&rhc->nonempty_instances); rhc->topic = topic; rhc->reader = reader; rhc->tkmap = gv->m_tkmap; @@ -814,7 +791,7 @@ static void dds_rhc_default_free (struct dds_rhc_default *rhc) lifespan_fini (&rhc->lifespan); #endif ddsrt_hh_enum (rhc->instances, free_instance_rhc_free_wrap, rhc); - assert (rhc->nonempty_instances == NULL); + assert (ddsrt_circlist_isempty (&rhc->nonempty_instances)); ddsrt_hh_free (rhc->instances); lwregs_fini (&rhc->registrations); if (rhc->qcond_eval_samplebuf != NULL) @@ -1966,10 +1943,10 @@ static int dds_rhc_read_w_qminv (struct dds_rhc_default *rhc, bool lock, void ** rhc->n_not_alive_no_writers, rhc->n_new, rhc->n_vsamples, rhc->n_invsamples, rhc->n_vread, rhc->n_invread); - if (rhc->nonempty_instances) + if (!ddsrt_circlist_isempty (&rhc->nonempty_instances)) { const dds_querycond_mask_t qcmask = (cond && cond->m_query.m_filter) ? cond->m_query.m_qcmask : 0; - struct rhc_instance * inst = rhc->nonempty_instances->next; + struct rhc_instance * inst = oldest_nonempty_instance (rhc); struct rhc_instance * const end = inst; do { @@ -2055,7 +2032,7 @@ static int dds_rhc_read_w_qminv (struct dds_rhc_default *rhc, bool lock, void ** break; } } - inst = inst->next; + inst = next_nonempty_instance (inst); } while (inst != end && n < max_samples); } @@ -2083,14 +2060,14 @@ static int dds_rhc_take_w_qminv (struct dds_rhc_default *rhc, bool lock, void ** rhc->n_not_alive_no_writers, rhc->n_new, rhc->n_vsamples, rhc->n_invsamples, rhc->n_vread, rhc->n_invread); - if (rhc->nonempty_instances) + if (!ddsrt_circlist_isempty (&rhc->nonempty_instances)) { const dds_querycond_mask_t qcmask = (cond && cond->m_query.m_filter) ? cond->m_query.m_qcmask : 0; - struct rhc_instance *inst = rhc->nonempty_instances->next; + struct rhc_instance *inst = oldest_nonempty_instance (rhc); unsigned n_insts = rhc->n_nonempty_instances; while (n_insts-- > 0 && n < max_samples) { - struct rhc_instance * const inst1 = inst->next; + struct rhc_instance * const inst1 = next_nonempty_instance (inst); iid = inst->iid; if (handle == DDS_HANDLE_NIL || iid == handle) { @@ -2238,14 +2215,14 @@ static int dds_rhc_takecdr_w_qminv (struct dds_rhc_default *rhc, bool lock, stru rhc->n_not_alive_no_writers, rhc->n_new, rhc->n_vsamples, rhc->n_invsamples, rhc->n_vread, rhc->n_invread); - if (rhc->nonempty_instances) + if (!ddsrt_circlist_isempty (&rhc->nonempty_instances)) { const dds_querycond_mask_t qcmask = (cond && cond->m_query.m_filter) ? cond->m_query.m_qcmask : 0; - struct rhc_instance *inst = rhc->nonempty_instances->next; + struct rhc_instance *inst = oldest_nonempty_instance (rhc); unsigned n_insts = rhc->n_nonempty_instances; while (n_insts-- > 0 && n < max_samples) { - struct rhc_instance * const inst1 = inst->next; + struct rhc_instance * const inst1 = next_nonempty_instance (inst); iid = inst->iid; if (handle == DDS_HANDLE_NIL || iid == handle) { @@ -2454,13 +2431,14 @@ static bool dds_rhc_default_add_readcondition (struct dds_rhc_default *rhc, dds_ { /* Read condition is not cached inside the instances and samples, so it only needs to be evaluated on the non-empty instances */ - if (rhc->nonempty_instances) + if (!ddsrt_circlist_isempty (&rhc->nonempty_instances)) { - struct rhc_instance *inst = rhc->nonempty_instances; + struct rhc_instance *inst = latest_nonempty_instance (rhc); + struct rhc_instance const * const end = inst; do { trigger += rhc_get_cond_trigger (inst, cond); - inst = inst->next; - } while (inst != rhc->nonempty_instances); + inst = next_nonempty_instance (inst); + } while (inst != end); } } else @@ -2904,26 +2882,25 @@ static int rhc_check_counts_locked (struct dds_rhc_default *rhc, bool check_cond { 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) { - assert (rhc->nonempty_instances == NULL); + assert (ddsrt_circlist_isempty (&rhc->nonempty_instances)); } else { - struct rhc_instance *prev, *end; - assert (rhc->nonempty_instances != NULL); - prev = rhc->nonempty_instances->prev; - end = rhc->nonempty_instances; - inst = rhc->nonempty_instances; + assert (!ddsrt_circlist_isempty (&rhc->nonempty_instances)); + struct ddsrt_circlist_elem const *prev = rhc->nonempty_instances.latest->prev; + inst = latest_nonempty_instance (rhc); + struct rhc_instance const * const end = inst; n_nonempty_instances = 0; do { assert (!inst_is_empty (inst)); - assert (prev->next == inst); - assert (inst->prev == prev); - prev = inst; - inst = inst->next; + assert (prev->next == &inst->nonempty_list); + assert (inst->nonempty_list.prev == prev); + prev = &inst->nonempty_list; + inst = next_nonempty_instance (inst); n_nonempty_instances++; } while (inst != end); assert (rhc->n_nonempty_instances == n_nonempty_instances); diff --git a/src/ddsrt/CMakeLists.txt b/src/ddsrt/CMakeLists.txt index b750b0c..8525a94 100644 --- a/src/ddsrt/CMakeLists.txt +++ b/src/ddsrt/CMakeLists.txt @@ -101,6 +101,10 @@ set(include_path "${CMAKE_CURRENT_SOURCE_DIR}/include") set(source_path "${CMAKE_CURRENT_SOURCE_DIR}/src") list(APPEND headers + "${include_path}/dds/ddsrt/avl.h" + "${include_path}/dds/ddsrt/fibheap.h" + "${include_path}/dds/ddsrt/hopscotch.h" + "${include_path}/dds/ddsrt/thread_pool.h" "${include_path}/dds/ddsrt/log.h" "${include_path}/dds/ddsrt/retcode.h" "${include_path}/dds/ddsrt/attributes.h" @@ -113,7 +117,8 @@ list(APPEND headers "${include_path}/dds/ddsrt/strtol.h" "${include_path}/dds/ddsrt/types.h" "${include_path}/dds/ddsrt/countargs.h" - "${include_path}/dds/ddsrt/static_assert.h") + "${include_path}/dds/ddsrt/static_assert.h" + "${include_path}/dds/ddsrt/circlist.h") list(APPEND sources "${source_path}/bswap.c" @@ -121,21 +126,14 @@ list(APPEND sources "${source_path}/log.c" "${source_path}/retcode.c" "${source_path}/strtod.c" - "${source_path}/strtol.c") - -list(APPEND headers - "${include_path}/dds/ddsrt/avl.h" - "${include_path}/dds/ddsrt/fibheap.h" - "${include_path}/dds/ddsrt/hopscotch.h" - "${include_path}/dds/ddsrt/thread_pool.h") - -list(APPEND sources + "${source_path}/strtol.c" "${source_path}/avl.c" "${source_path}/expand_envvars.c" "${source_path}/fibheap.c" "${source_path}/hopscotch.c" "${source_path}/thread_pool.c" - "${source_path}/xmlparser.c") + "${source_path}/xmlparser.c" + "${source_path}/circlist.c") # Not every target offers the same set of features. For embedded targets the # set of features may even be different between builds. e.g. a FreeRTOS build diff --git a/src/ddsrt/include/dds/ddsrt/circlist.h b/src/ddsrt/include/dds/ddsrt/circlist.h new file mode 100644 index 0000000..3c4ca56 --- /dev/null +++ b/src/ddsrt/include/dds/ddsrt/circlist.h @@ -0,0 +1,43 @@ +/* + * 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 + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#ifndef DDSRT_CIRCLIST_H +#define DDSRT_CIRCLIST_H + +/* Circular doubly linked list implementation */ + +#include +#include +#include "dds/export.h" + +#if defined (__cplusplus) +extern "C" { +#endif + +#define DDSRT_FROM_CIRCLIST(typ_, member_, cle_) ((typ_ *) ((char *) (cle_) - offsetof (typ_, member_))) + +struct ddsrt_circlist { + struct ddsrt_circlist_elem *latest; /* pointer to latest inserted element */ +}; + +struct ddsrt_circlist_elem { + struct ddsrt_circlist_elem *next; + struct ddsrt_circlist_elem *prev; +}; + +DDS_EXPORT void ddsrt_circlist_init (struct ddsrt_circlist *list); +DDS_EXPORT bool ddsrt_circlist_isempty (const struct ddsrt_circlist *list); +DDS_EXPORT void ddsrt_circlist_append (struct ddsrt_circlist *list, struct ddsrt_circlist_elem *elem); +DDS_EXPORT void ddsrt_circlist_remove (struct ddsrt_circlist *list, struct ddsrt_circlist_elem *elem); +DDS_EXPORT struct ddsrt_circlist_elem *ddsrt_circlist_oldest (const struct ddsrt_circlist *list); +DDS_EXPORT struct ddsrt_circlist_elem *ddsrt_circlist_latest (const struct ddsrt_circlist *list); + +#endif /* DDSRT_CIRCLIST_H */ \ No newline at end of file diff --git a/src/ddsrt/src/circlist.c b/src/ddsrt/src/circlist.c new file mode 100644 index 0000000..51159bd --- /dev/null +++ b/src/ddsrt/src/circlist.c @@ -0,0 +1,84 @@ +/* + * 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 + * 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 +#include +#include +#include +#include "dds/ddsrt/circlist.h" + +void ddsrt_circlist_init (struct ddsrt_circlist *list) +{ + list->latest = NULL; +} + +bool ddsrt_circlist_isempty (const struct ddsrt_circlist *list) +{ + return list->latest == NULL; +} + +void ddsrt_circlist_append (struct ddsrt_circlist *list, struct ddsrt_circlist_elem *elem) +{ + if (list->latest == NULL) + elem->next = elem->prev = elem; + else + { + struct ddsrt_circlist_elem * const hd = list->latest; +#ifndef NDEBUG + { + const struct ddsrt_circlist_elem *x = hd; + do { assert (x != elem); x = x->next; } while (x != hd); + } +#endif + elem->next = hd->next; + elem->prev = hd; + hd->next = elem; + elem->next->prev = elem; + } + list->latest = elem; +} + +void ddsrt_circlist_remove (struct ddsrt_circlist *list, struct ddsrt_circlist_elem *elem) +{ +#ifndef NDEBUG + { + const struct ddsrt_circlist_elem *x = list->latest; + assert (x); + do { if (x == elem) break; x = x->next; } while (x != list->latest); + assert (x == elem); + } +#endif + if (elem->next == elem) + list->latest = NULL; + else + { + struct ddsrt_circlist_elem * const elem_prev = elem->prev; + struct ddsrt_circlist_elem * const elem_next = elem->next; + elem_prev->next = elem_next; + elem_next->prev = elem_prev; + if (list->latest == elem) + list->latest = elem_prev; + } +} + +struct ddsrt_circlist_elem *ddsrt_circlist_oldest (const struct ddsrt_circlist *list) +{ + assert (!ddsrt_circlist_isempty (list)); + return list->latest->next; +} + +struct ddsrt_circlist_elem *ddsrt_circlist_latest (const struct ddsrt_circlist *list) +{ + assert (!ddsrt_circlist_isempty (list)); + return list->latest; +} + +