Small entity deletion wip refactoring.
Signed-off-by: Martin Bremmer <martin.bremmer@adlinktech.com>
This commit is contained in:
parent
40973d8e29
commit
fc8b8fef3a
3 changed files with 93 additions and 96 deletions
|
@ -48,7 +48,7 @@ static int dds_domain_compare (const void *va, const void *vb)
|
|||
static const ddsrt_avl_treedef_t dds_domaintree_def = DDSRT_AVL_TREEDEF_INITIALIZER (
|
||||
offsetof (dds_domain, m_node), offsetof (dds_domain, m_id), dds_domain_compare, 0);
|
||||
|
||||
static dds_return_t dds_domain_init (dds_domain *domain, dds_domainid_t domain_id, const char *config, bool implicit)
|
||||
static dds_entity_t dds_domain_init (dds_domain *domain, dds_domainid_t domain_id, const char *config, bool implicit)
|
||||
{
|
||||
dds_entity_t domh;
|
||||
uint32_t len;
|
||||
|
@ -193,27 +193,37 @@ dds_domain *dds_domain_find_locked (dds_domainid_t id)
|
|||
dds_entity_t dds_domain_create_internal (dds_domain **domain_out, dds_domainid_t id, bool implicit, const char *config)
|
||||
{
|
||||
struct dds_domain *dom;
|
||||
dds_entity_t domh;
|
||||
dds_entity_t domh = DDS_RETCODE_ERROR;
|
||||
|
||||
/* FIXME: should perhaps lock parent object just like everywhere */
|
||||
ddsrt_mutex_lock (&dds_global.m_mutex);
|
||||
retry:
|
||||
if (id != DDS_DOMAIN_DEFAULT)
|
||||
dom = dds_domain_find_locked (id);
|
||||
else
|
||||
dom = ddsrt_avl_find_min (&dds_domaintree_def, &dds_global.m_domains);
|
||||
|
||||
if (dom)
|
||||
{
|
||||
if ((dom = dds_domain_find_locked (id)) == NULL)
|
||||
domh = DDS_RETCODE_NOT_FOUND;
|
||||
if (!implicit)
|
||||
domh = DDS_RETCODE_PRECONDITION_NOT_MET;
|
||||
else
|
||||
{
|
||||
ddsrt_mutex_lock (&dom->m_entity.m_mutex);
|
||||
if (dds_handle_is_closed (&dom->m_entity.m_hdllink))
|
||||
{
|
||||
ddsrt_mutex_unlock (&dom->m_entity.m_mutex);
|
||||
ddsrt_cond_wait (&dds_global.m_cond, &dds_global.m_mutex);
|
||||
goto retry;
|
||||
}
|
||||
dds_entity_add_ref_locked (&dom->m_entity);
|
||||
dds_handle_repin (&dom->m_entity.m_hdllink);
|
||||
domh = dom->m_entity.m_hdllink.hdl;
|
||||
ddsrt_mutex_unlock (&dom->m_entity.m_mutex);
|
||||
*domain_out = dom;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((dom = ddsrt_avl_find_min (&dds_domaintree_def, &dds_global.m_domains)) != NULL)
|
||||
domh = dom->m_entity.m_hdllink.hdl;
|
||||
else
|
||||
domh = DDS_RETCODE_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (domh == DDS_RETCODE_NOT_FOUND)
|
||||
{
|
||||
dom = dds_alloc (sizeof (*dom));
|
||||
if ((domh = dds_domain_init (dom, id, config, implicit)) < 0)
|
||||
|
@ -228,35 +238,7 @@ dds_entity_t dds_domain_create_internal (dds_domain **domain_out, dds_domainid_t
|
|||
dds_entity_add_ref_locked (&dom->m_entity);
|
||||
dds_handle_repin (&dom->m_entity.m_hdllink);
|
||||
}
|
||||
ddsrt_mutex_unlock (&dom->m_entity.m_mutex);
|
||||
*domain_out = dom;
|
||||
}
|
||||
}
|
||||
else if (domh <= DDS_RETCODE_OK)
|
||||
{
|
||||
assert (0);
|
||||
domh = DDS_RETCODE_ERROR;
|
||||
}
|
||||
else if (!implicit)
|
||||
{
|
||||
domh = DDS_RETCODE_PRECONDITION_NOT_MET;
|
||||
}
|
||||
else
|
||||
{
|
||||
ddsrt_mutex_lock (&dom->m_entity.m_mutex);
|
||||
if (dds_handle_is_closed (&dom->m_entity.m_hdllink))
|
||||
{
|
||||
ddsrt_mutex_unlock (&dom->m_entity.m_mutex);
|
||||
ddsrt_cond_wait (&dds_global.m_cond, &dds_global.m_mutex);
|
||||
goto retry;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (implicit)
|
||||
{
|
||||
dds_entity_add_ref_locked (&dom->m_entity);
|
||||
dds_handle_repin (&dom->m_entity.m_hdllink);
|
||||
}
|
||||
domh = dom->m_entity.m_hdllink.hdl;
|
||||
ddsrt_mutex_unlock (&dom->m_entity.m_mutex);
|
||||
*domain_out = dom;
|
||||
}
|
||||
|
|
|
@ -92,10 +92,7 @@ void dds_entity_drop_ref (dds_entity *e)
|
|||
{
|
||||
if (dds_handle_drop_ref (&e->m_hdllink))
|
||||
{
|
||||
/* increment pin count unconditionally to satisfy the "pinned" requirement */
|
||||
dds_handle_repin (&e->m_hdllink);
|
||||
ddsrt_mutex_lock (&e->m_mutex);
|
||||
dds_return_t ret = really_delete_pinned_closed_locked (e, DIS_EXPLICIT);
|
||||
dds_return_t ret = dds_delete_impl(e->m_hdllink.hdl, DIS_EXPLICIT);
|
||||
assert (ret == DDS_RETCODE_OK);
|
||||
(void) ret;
|
||||
}
|
||||
|
@ -105,10 +102,7 @@ void dds_entity_unpin_and_drop_ref (dds_entity *e)
|
|||
{
|
||||
if (dds_handle_unpin_and_drop_ref (&e->m_hdllink))
|
||||
{
|
||||
/* increment pin count unconditionally to satisfy the "pinned" requirement */
|
||||
dds_handle_repin (&e->m_hdllink);
|
||||
ddsrt_mutex_lock (&e->m_mutex);
|
||||
dds_return_t ret = really_delete_pinned_closed_locked (e, DIS_EXPLICIT);
|
||||
dds_return_t ret = dds_delete_impl(e->m_hdllink.hdl, DIS_EXPLICIT);
|
||||
assert (ret == DDS_RETCODE_OK);
|
||||
(void) ret;
|
||||
}
|
||||
|
@ -223,17 +217,45 @@ void dds_entity_register_child (dds_entity *parent, dds_entity *child)
|
|||
dds_entity_add_ref_locked (parent);
|
||||
}
|
||||
|
||||
static dds_entity *next_non_topic_child (ddsrt_avl_tree_t *remaining_children)
|
||||
static dds_entity *get_first_child (ddsrt_avl_tree_t *remaining_children, bool ignore_topics)
|
||||
{
|
||||
ddsrt_avl_iter_t it;
|
||||
for (dds_entity *e = ddsrt_avl_iter_first (&dds_entity_children_td, remaining_children, &it); e != NULL; e = ddsrt_avl_iter_next (&it))
|
||||
{
|
||||
if (dds_entity_kind (e) != DDS_KIND_TOPIC)
|
||||
if ((!ignore_topics) || (dds_entity_kind(e) != DDS_KIND_TOPIC))
|
||||
return e;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void delete_children(struct dds_entity *parent, bool ignore_topics)
|
||||
{
|
||||
dds_entity *child;
|
||||
dds_return_t ret;
|
||||
ddsrt_mutex_lock (&parent->m_mutex);
|
||||
while ((child = get_first_child(&parent->m_children, ignore_topics)) != NULL)
|
||||
{
|
||||
dds_entity_t child_handle = child->m_hdllink.hdl;
|
||||
|
||||
/* The child will remove itself from the parent->m_children list. */
|
||||
ddsrt_mutex_unlock (&parent->m_mutex);
|
||||
ret = dds_delete_impl (child_handle, DIS_FROM_PARENT);
|
||||
assert (ret == DDS_RETCODE_OK || ret == DDS_RETCODE_BAD_PARAMETER);
|
||||
ddsrt_mutex_lock (&parent->m_mutex);
|
||||
|
||||
/* The dds_delete can fail if the child is being deleted in parallel,
|
||||
* in which case: wait when its not deleted yet.
|
||||
* The child will trigger the condition after it removed itself from
|
||||
* the childrens list. */
|
||||
if ((ret == DDS_RETCODE_BAD_PARAMETER) &&
|
||||
(get_first_child(&parent->m_children, ignore_topics) == child))
|
||||
{
|
||||
ddsrt_cond_wait (&parent->m_cond, &parent->m_mutex);
|
||||
}
|
||||
}
|
||||
ddsrt_mutex_unlock (&parent->m_mutex);
|
||||
}
|
||||
|
||||
#define TRACE_DELETE 0 /* FIXME: use DDS_LOG for this */
|
||||
#if TRACE_DELETE
|
||||
static const char *entity_kindstr (dds_entity_kind_t kind)
|
||||
|
@ -312,7 +334,6 @@ dds_return_t dds_delete_impl_pinned (dds_entity *e, enum delete_impl_state delst
|
|||
|
||||
static dds_return_t really_delete_pinned_closed_locked (struct dds_entity *e, enum delete_impl_state delstate)
|
||||
{
|
||||
dds_entity *child;
|
||||
dds_return_t ret;
|
||||
|
||||
/* No threads pinning it anymore, no need to worry about other threads deleting
|
||||
|
@ -369,32 +390,8 @@ static dds_return_t really_delete_pinned_closed_locked (struct dds_entity *e, en
|
|||
*
|
||||
* To circumvent the problem. We ignore topics in the first loop.
|
||||
*/
|
||||
ddsrt_mutex_lock (&e->m_mutex);
|
||||
while ((child = next_non_topic_child (&e->m_children)) != NULL)
|
||||
{
|
||||
/* FIXME: dds_delete can fail if the child is being deleted in parallel, in which case: wait */
|
||||
dds_entity_t child_handle = child->m_hdllink.hdl;
|
||||
ddsrt_mutex_unlock (&e->m_mutex);
|
||||
ret = dds_delete_impl (child_handle, DIS_FROM_PARENT);
|
||||
assert (ret == DDS_RETCODE_OK || ret == DDS_RETCODE_BAD_PARAMETER);
|
||||
(void) ret;
|
||||
ddsrt_mutex_lock (&e->m_mutex);
|
||||
if (ret == DDS_RETCODE_BAD_PARAMETER && child == next_non_topic_child (&e->m_children))
|
||||
{
|
||||
ddsrt_cond_wait (&e->m_cond, &e->m_mutex);
|
||||
}
|
||||
}
|
||||
while ((child = ddsrt_avl_find_min (&dds_entity_children_td, &e->m_children)) != NULL)
|
||||
{
|
||||
assert (dds_entity_kind (child) == DDS_KIND_TOPIC);
|
||||
dds_entity_t child_handle = child->m_hdllink.hdl;
|
||||
ddsrt_mutex_unlock (&e->m_mutex);
|
||||
ret = dds_delete_impl (child_handle, DIS_FROM_PARENT);
|
||||
assert (ret == DDS_RETCODE_OK);
|
||||
(void) ret;
|
||||
ddsrt_mutex_lock (&e->m_mutex);
|
||||
}
|
||||
ddsrt_mutex_unlock (&e->m_mutex);
|
||||
delete_children(e, true /* ignore topics */);
|
||||
delete_children(e, false /* delete topics */);
|
||||
|
||||
/* The dds_handle_delete will wait until the last active claim on that handle is
|
||||
released. It is possible that this last release will be done by a thread that was
|
||||
|
@ -416,6 +413,7 @@ static dds_return_t really_delete_pinned_closed_locked (struct dds_entity *e, en
|
|||
ddsrt_avl_delete (&dds_entity_children_td, &p->m_children, e);
|
||||
if (dds_handle_drop_childref_and_pin (&p->m_hdllink, delstate != DIS_FROM_PARENT))
|
||||
{
|
||||
dds_handle_close(&p->m_hdllink);
|
||||
assert (dds_handle_is_closed (&p->m_hdllink));
|
||||
assert (dds_handle_is_not_refd (&p->m_hdllink));
|
||||
assert (ddsrt_avl_is_empty (&p->m_children));
|
||||
|
|
|
@ -294,8 +294,16 @@ int32_t dds_handle_pin_for_delete (dds_handle_t hdl, bool explicit, struct dds_h
|
|||
outstanding references. This implies that there are no children, because then the
|
||||
entire hierarchy would simply have been deleted. */
|
||||
assert (!(cf & HDL_FLAG_ALLOW_CHILDREN));
|
||||
rc = DDS_RETCODE_ALREADY_DELETED;
|
||||
break;
|
||||
if (cf & HDL_REFCOUNT_MASK)
|
||||
{
|
||||
rc = DDS_RETCODE_ALREADY_DELETED;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Refcount reached zero. Pin to allow deletion. */
|
||||
cf1 = (cf + 1u) | HDL_FLAG_CLOSING;
|
||||
}
|
||||
}
|
||||
else if (explicit)
|
||||
{
|
||||
|
@ -305,21 +313,24 @@ int32_t dds_handle_pin_for_delete (dds_handle_t hdl, bool explicit, struct dds_h
|
|||
/* Entity is implicit, so handle doesn't hold a reference */
|
||||
cf1 = (cf + 1u) | HDL_FLAG_CLOSING;
|
||||
}
|
||||
else if (cf & HDL_FLAG_ALLOW_CHILDREN)
|
||||
{
|
||||
/* Entity is explicit, so handle held a reference, refc only counts children as so is not our concern */
|
||||
assert ((cf & HDL_REFCOUNT_MASK) > 0);
|
||||
cf1 = (cf - HDL_REFCOUNT_UNIT + 1u) | HDL_FLAG_CLOSING;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Entity is explicit, so handle held a reference, refc counts non-children, refc > 1 means drop ref and error (so don't pin) */
|
||||
assert ((cf & HDL_REFCOUNT_MASK) > 0);
|
||||
if ((cf & HDL_REFCOUNT_MASK) == HDL_REFCOUNT_UNIT)
|
||||
{
|
||||
/* Last reference is closing. Pin entity and indicate that it is closing. */
|
||||
cf1 = (cf - HDL_REFCOUNT_UNIT + 1u) | HDL_FLAG_CLOSING;
|
||||
}
|
||||
else if (!(cf & HDL_FLAG_ALLOW_CHILDREN))
|
||||
{
|
||||
/* The refcnt does not contain children.
|
||||
* Indicate that the closing of the entity is deferred. */
|
||||
cf1 = (cf - HDL_REFCOUNT_UNIT) | HDL_FLAG_DELETE_DEFERRED;
|
||||
}
|
||||
else
|
||||
{
|
||||
cf1 = (cf - HDL_REFCOUNT_UNIT) | HDL_FLAG_DELETE_DEFERRED;
|
||||
/* Entity is explicit, so handle held a reference, refc only counts children as so is not our concern */
|
||||
cf1 = (cf - HDL_REFCOUNT_UNIT + 1u) | HDL_FLAG_CLOSING;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -328,11 +339,21 @@ int32_t dds_handle_pin_for_delete (dds_handle_t hdl, bool explicit, struct dds_h
|
|||
/* Implicit call to dds_delete (child invoking delete on its parent) */
|
||||
if (cf & HDL_FLAG_IMPLICIT)
|
||||
{
|
||||
assert ((cf & HDL_REFCOUNT_MASK) > 0);
|
||||
if ((cf & HDL_REFCOUNT_MASK) == HDL_REFCOUNT_UNIT)
|
||||
{
|
||||
/* Last reference is closing. Pin entity and indicate that it is closing. */
|
||||
cf1 = (cf - HDL_REFCOUNT_UNIT + 1u) | HDL_FLAG_CLOSING;
|
||||
}
|
||||
else if (!(cf & HDL_FLAG_ALLOW_CHILDREN))
|
||||
{
|
||||
/* The refcnt does not contain children.
|
||||
* Indicate that the closing of the entity is deferred. */
|
||||
cf1 = (cf - HDL_REFCOUNT_UNIT) | HDL_FLAG_DELETE_DEFERRED;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert ((cf & HDL_REFCOUNT_MASK) > 0);
|
||||
/* Just reduce the children refcount by one. */
|
||||
cf1 = (cf - HDL_REFCOUNT_UNIT);
|
||||
}
|
||||
}
|
||||
|
@ -373,7 +394,7 @@ bool dds_handle_drop_childref_and_pin (struct dds_handle_link *link, bool may_de
|
|||
/* Implicit parent: delete if last ref */
|
||||
if ((cf & HDL_REFCOUNT_MASK) == HDL_REFCOUNT_UNIT && may_delete_parent)
|
||||
{
|
||||
cf1 = (cf - HDL_REFCOUNT_UNIT + 1u) | HDL_FLAG_CLOSING;
|
||||
cf1 = (cf - HDL_REFCOUNT_UNIT + 1u);
|
||||
del_parent = true;
|
||||
}
|
||||
else
|
||||
|
@ -436,8 +457,6 @@ bool dds_handle_drop_ref (struct dds_handle_link *link)
|
|||
old = ddsrt_atomic_ld32 (&link->cnt_flags);
|
||||
assert ((old & HDL_REFCOUNT_MASK) > 0);
|
||||
new = old - HDL_REFCOUNT_UNIT;
|
||||
if ((old & HDL_REFCOUNT_MASK) == HDL_REFCOUNT_UNIT)
|
||||
new |= HDL_FLAG_CLOSING;
|
||||
} while (!ddsrt_atomic_cas32 (&link->cnt_flags, old, new));
|
||||
ddsrt_mutex_lock (&handles.lock);
|
||||
if ((new & (HDL_FLAG_CLOSING | HDL_PINCOUNT_MASK)) == (HDL_FLAG_CLOSING | 1u))
|
||||
|
@ -445,7 +464,7 @@ bool dds_handle_drop_ref (struct dds_handle_link *link)
|
|||
ddsrt_cond_broadcast (&handles.cond);
|
||||
}
|
||||
ddsrt_mutex_unlock (&handles.lock);
|
||||
return (new & (HDL_FLAG_CLOSING | HDL_REFCOUNT_MASK)) == (HDL_FLAG_CLOSING | 0);
|
||||
return ((new & HDL_REFCOUNT_MASK) == 0);
|
||||
}
|
||||
|
||||
bool dds_handle_unpin_and_drop_ref (struct dds_handle_link *link)
|
||||
|
@ -456,8 +475,6 @@ bool dds_handle_unpin_and_drop_ref (struct dds_handle_link *link)
|
|||
assert ((old & HDL_REFCOUNT_MASK) > 0);
|
||||
assert ((old & HDL_PINCOUNT_MASK) > 0);
|
||||
new = old - HDL_REFCOUNT_UNIT - 1u;
|
||||
if ((old & HDL_REFCOUNT_MASK) == HDL_REFCOUNT_UNIT && (old & HDL_FLAG_IMPLICIT))
|
||||
new |= HDL_FLAG_CLOSING;
|
||||
} while (!ddsrt_atomic_cas32 (&link->cnt_flags, old, new));
|
||||
ddsrt_mutex_lock (&handles.lock);
|
||||
if ((new & (HDL_FLAG_CLOSING | HDL_PINCOUNT_MASK)) == (HDL_FLAG_CLOSING | 1u))
|
||||
|
@ -465,7 +482,7 @@ bool dds_handle_unpin_and_drop_ref (struct dds_handle_link *link)
|
|||
ddsrt_cond_broadcast (&handles.cond);
|
||||
}
|
||||
ddsrt_mutex_unlock (&handles.lock);
|
||||
return (new & (HDL_FLAG_CLOSING | HDL_REFCOUNT_MASK)) == (HDL_FLAG_CLOSING | 0);
|
||||
return ((new & HDL_REFCOUNT_MASK) == 0);
|
||||
}
|
||||
|
||||
bool dds_handle_close (struct dds_handle_link *link)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue