-
Notifications
You must be signed in to change notification settings - Fork 357
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Entity enable #530
base: master
Are you sure you want to change the base?
Entity enable #530
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -202,6 +202,23 @@ static struct ddsi_tkmap_instance *dds__builtin_get_tkmap_entry (const struct dd | |
return tk; | ||
} | ||
|
||
static struct ddsi_tkmap_instance *dds__builtin_get_tkmap_entry_with_iid (const struct ddsi_guid *guid, const uint64_t iid, void *vdomain) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This function serves a rather unique purpose: new local entities now need to have an Technically, the possibility exists that a GUID gets reused, there are after all but 2^24 entity ids (in Cyclone, arguably different entity kinds could use the same entity id). So a process that creates 2^24 entities (but for some rounding errors), deletes one of them (so there is again an entity id available), and then creates another entity will necessarily reuse the entity id of the entity that was just deleted. However the GUID-to-iid mapping may outlive the entity that was deleted. Consequently, in the design in this PR, come the call Methinks the solution lies in not introducing this new path, but rather moving the GUID allocation (e.g., in (This has various effects throughout the PR, I'm not going to mark them, that's not worth the bother.) |
||
{ | ||
struct dds_domain *domain = vdomain; | ||
struct ddsi_tkmap_instance *tk; | ||
struct ddsi_serdata *sd; | ||
union { ddsi_guid_t guid; struct ddsi_keyhash keyhash; } x; | ||
x.guid = nn_hton_guid (*guid); | ||
/* any random builtin topic will do (provided it has a GUID for a key), because what matters is the "class" | ||
of the topic, not the actual topic; also, this is called early in the initialisation of the entity with | ||
this GUID, which simply causes serdata_from_keyhash to create a key-only serdata because the key lookup | ||
fails. */ | ||
sd = ddsi_serdata_from_keyhash (domain->builtin_participant_type, &x.keyhash); | ||
tk = ddsi_tkmap_find_with_iid (domain->gv.m_tkmap, sd, iid, true); | ||
ddsi_serdata_unref (sd); | ||
return tk; | ||
} | ||
|
||
struct ddsi_serdata *dds__builtin_make_sample (const struct entity_common *e, ddsrt_wctime_t timestamp, bool alive) | ||
{ | ||
/* initialize to avoid gcc warning ultimately caused by C's horrible type system */ | ||
|
@@ -273,6 +290,7 @@ void dds__builtin_init (struct dds_domain *dom) | |
|
||
dom->btif.arg = dom; | ||
dom->btif.builtintopic_get_tkmap_entry = dds__builtin_get_tkmap_entry; | ||
dom->btif.builtintopic_get_tkmap_entry_with_iid = dds__builtin_get_tkmap_entry_with_iid; | ||
dom->btif.builtintopic_is_builtintopic = dds__builtin_is_builtintopic; | ||
dom->btif.builtintopic_is_visible = dds__builtin_is_visible; | ||
dom->btif.builtintopic_write = dds__builtin_write; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -68,6 +68,9 @@ struct dds_statistics *dds_entity_deriver_dummy_create_statistics (const struct | |
void dds_entity_deriver_dummy_refresh_statistics (const struct dds_entity *e, struct dds_statistics *s) { | ||
(void) e; (void) s; | ||
} | ||
dds_return_t dds_entity_deriver_dummy_enable (struct dds_entity *e) { | ||
(void) e; return DDS_RETCODE_ILLEGAL_OPERATION; | ||
} | ||
|
||
extern inline void dds_entity_deriver_interrupt (struct dds_entity *e); | ||
extern inline void dds_entity_deriver_close (struct dds_entity *e); | ||
|
@@ -78,6 +81,7 @@ extern inline bool dds_entity_supports_set_qos (struct dds_entity *e); | |
extern inline bool dds_entity_supports_validate_status (struct dds_entity *e); | ||
extern inline struct dds_statistics *dds_entity_deriver_create_statistics (const struct dds_entity *e); | ||
extern inline void dds_entity_deriver_refresh_statistics (const struct dds_entity *e, struct dds_statistics *s); | ||
extern inline dds_return_t dds_entity_deriver_enable (struct dds_entity *e); | ||
|
||
static int compare_instance_handle (const void *va, const void *vb) | ||
{ | ||
|
@@ -196,6 +200,46 @@ static bool entity_kind_has_qos (dds_entity_kind_t kind) | |
} | ||
#endif | ||
|
||
dds_return_t dds_entity_autoenable_children (dds_entity *e) | ||
{ | ||
struct dds_entity *c; | ||
ddsrt_avl_iter_t it; | ||
dds_return_t rc = DDS_RETCODE_OK, ret; | ||
|
||
assert(e); | ||
assert(e->m_flags & DDS_ENTITY_ENABLED); | ||
|
||
/* enable all disabled children with the flag DDS_ENTITY_ENABLE_ON_PARENT */ | ||
for (c = ddsrt_avl_iter_first (&dds_entity_children_td, &e->m_children, &it); c != NULL; c = ddsrt_avl_iter_next (&it)) { | ||
if ((!(c->m_flags & DDS_ENTITY_ENABLED)) && (c->m_flags & DDS_ENTITY_ENABLE_ON_PARENT)) { | ||
ret = dds_enable((dds_entity_t)c->m_hdllink.hdl); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is invoked by the entity kind-specific function on So here is a risk of deadlock, however small (there are rather few operations that would actually try to lock a disabled entity, but certainly calling The trick to do such a walk over entities typically involves unlocking & relocking the parent entity. See, for example, |
||
if ((rc == DDS_RETCODE_OK) && (ret < 0)) { | ||
rc = ret; | ||
} | ||
} | ||
} | ||
return rc; | ||
} | ||
|
||
static void dds_entity_init_mflags (dds_entity *e, dds_entity *parent, bool implicit) | ||
{ | ||
assert (e); | ||
|
||
if (implicit) | ||
e->m_flags |= DDS_ENTITY_IMPLICIT; | ||
/* entity is enabled by default unless parent is not enabled or parent has | ||
* autoenable_created_entities set to false */ | ||
e->m_flags |= DDS_ENTITY_ENABLED; | ||
if (parent) { | ||
if (parent->m_qos && parent->m_qos->entity_factory.autoenable_created_entities) | ||
/* parent has autoenable set to true */ | ||
e->m_flags |= DDS_ENTITY_ENABLE_ON_PARENT; | ||
/* do not enable if parent is not enabled or no autoenable */ | ||
if ((!(parent->m_flags & DDS_ENTITY_ENABLED)) || ((e->m_flags & DDS_ENTITY_ENABLE_ON_PARENT) == 0)) | ||
e->m_flags &= ~DDS_ENTITY_ENABLED; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think rewriting the logic to set |
||
} | ||
} | ||
|
||
dds_entity_t dds_entity_init (dds_entity *e, dds_entity *parent, dds_entity_kind_t kind, bool implicit, dds_qos_t *qos, const dds_listener_t *listener, status_mask_t mask) | ||
{ | ||
dds_handle_t handle; | ||
|
@@ -211,10 +255,10 @@ dds_entity_t dds_entity_init (dds_entity *e, dds_entity *parent, dds_entity_kind | |
e->m_cb_pending_count = 0; | ||
e->m_observers = NULL; | ||
|
||
/* TODO: CHAM-96: Implement dynamic enabling of entity. */ | ||
e->m_flags |= DDS_ENTITY_ENABLED; | ||
if (implicit) | ||
e->m_flags |= DDS_ENTITY_IMPLICIT; | ||
/* All entities are enabled by default, except if the parent is not enabled or | ||
* if the parent's entity factory qos indicates that children of this parent | ||
* should not be enabled when created */ | ||
dds_entity_init_mflags (e, parent, implicit); | ||
|
||
/* set the status enable based on kind */ | ||
if (entity_has_status (e)) | ||
|
@@ -1059,15 +1103,11 @@ dds_return_t dds_enable (dds_entity_t entity) | |
|
||
if ((rc = dds_entity_lock (entity, DDS_KIND_DONTCARE, &e)) != DDS_RETCODE_OK) | ||
return rc; | ||
|
||
/* only enable entities that are not yet enabled */ | ||
if ((e->m_flags & DDS_ENTITY_ENABLED) == 0) | ||
{ | ||
/* TODO: Really enable. */ | ||
e->m_flags |= DDS_ENTITY_ENABLED; | ||
DDS_CERROR (&e->m_domain->gv.logconfig, "Delayed entity enabling is not supported\n"); | ||
} | ||
rc = dds_entity_deriver_enable(e); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This does make some sense (enabling is definitely specific to the entity kind), but it doesn't actually dispatch to an implementation for all entity kinds (e.g., what about topics? — and if those don't need any special handling, |
||
dds_entity_unlock (e); | ||
return DDS_RETCODE_OK; | ||
return rc; | ||
} | ||
|
||
dds_return_t dds_get_status_changes (dds_entity_t entity, uint32_t *status) | ||
|
@@ -1327,10 +1367,15 @@ dds_return_t dds_triggered (dds_entity_t entity) | |
|
||
if ((ret = dds_entity_lock (entity, DDS_KIND_DONTCARE, &e)) != DDS_RETCODE_OK) | ||
return ret; | ||
if (!dds_entity_is_enabled(e)) { | ||
ret = DDS_RETCODE_NOT_ENABLED; | ||
goto err_enabled; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is the same amount of code as dds_entity_unlock (e);
return DDS_RETCODE_NOT_ENABLED; in other words, the use of a |
||
} | ||
if (entity_has_status (e)) | ||
ret = ((ddsrt_atomic_ld32 (&e->m_status.m_status_and_mask) & SAM_STATUS_MASK) != 0); | ||
else | ||
ret = (ddsrt_atomic_ld32 (&e->m_status.m_trigger) != 0); | ||
err_enabled: | ||
dds_entity_unlock (e); | ||
return ret; | ||
} | ||
|
@@ -1546,3 +1591,13 @@ dds_return_t dds_assert_liveliness (dds_entity_t entity) | |
dds_entity_unpin (e); | ||
return rc; | ||
} | ||
|
||
bool dds_entity_creation_allowed (const dds_return_t rc) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think this function makes things clearer than simply inlining it at the two call sites. |
||
{ | ||
switch (rc) { | ||
case DDS_RETCODE_NOT_ALLOWED_BY_SECURITY: | ||
return false; | ||
default: | ||
return true; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not really a fan of this model — I'd rather see no change at all when the operation fails — but considering that it is a relatively rarely used operation and that I imagine failure will usually be treated as a grounds for program termination, I think this is fine for a first iteration.