fix race conditions in instance id-to-key lookup
this is just an intermediate step: firstly, iid-to-key lookup is a linear scan; secondly, the lookup should happen on the RHC or the WHC and not on some internal map to associates key values with instance handles and is independent of entities Signed-off-by: Erik Boasson <eb@ilities.com>
This commit is contained in:
parent
0f7ce1ac43
commit
179a35d192
3 changed files with 45 additions and 74 deletions
|
@ -250,9 +250,7 @@ dds_unregister_instance_ih_ts(
|
|||
bool autodispose = true;
|
||||
dds_write_action action = DDS_WR_ACTION_UNREGISTER;
|
||||
dds_entity *wr;
|
||||
struct ddsi_tkmap *map;
|
||||
const dds_topic *topic;
|
||||
void *sample;
|
||||
struct ddsi_tkmap_instance *tk;
|
||||
|
||||
rc = dds_entity_lock(writer, DDS_KIND_WRITER, &wr);
|
||||
if (rc != DDS_RETCODE_OK) {
|
||||
|
@ -269,19 +267,21 @@ dds_unregister_instance_ih_ts(
|
|||
action |= DDS_WR_DISPOSE_BIT;
|
||||
}
|
||||
|
||||
map = gv.m_tkmap;
|
||||
if (asleep) {
|
||||
thread_state_awake(thr);
|
||||
}
|
||||
topic = dds_instance_info((dds_entity*)wr);
|
||||
sample = ddsi_sertopic_alloc_sample (topic->m_stopic);
|
||||
if (ddsi_tkmap_get_key (map, topic->m_stopic, handle, sample)) {
|
||||
tk = ddsi_tkmap_find_by_id (gv.m_tkmap, handle);
|
||||
if (tk) {
|
||||
struct ddsi_sertopic *tp = ((dds_writer*) wr)->m_topic->m_stopic;
|
||||
void *sample = ddsi_sertopic_alloc_sample (tp);
|
||||
ddsi_serdata_topicless_to_sample (tp, tk->m_sample, sample, NULL, NULL);
|
||||
ddsi_tkmap_instance_unref (tk);
|
||||
ret = dds_write_impl ((dds_writer*)wr, sample, timestamp, action);
|
||||
ddsi_sertopic_free_sample (tp, sample, DDS_FREE_ALL);
|
||||
} else {
|
||||
DDS_ERROR("No instance related with the provided handle is found\n");
|
||||
ret = DDS_ERRNO(DDS_RETCODE_PRECONDITION_NOT_MET);
|
||||
}
|
||||
ddsi_sertopic_free_sample (topic->m_stopic, sample, DDS_FREE_ALL);
|
||||
if (asleep) {
|
||||
thread_state_asleep(thr);
|
||||
}
|
||||
|
@ -387,14 +387,17 @@ dds_dispose_ih_ts(
|
|||
if (rc == DDS_RETCODE_OK) {
|
||||
struct thread_state1 * const thr = lookup_thread_state();
|
||||
const bool asleep = !vtime_awake_p(thr->vtime);
|
||||
struct ddsi_tkmap *map = gv.m_tkmap;
|
||||
const dds_topic *topic = dds_instance_info((dds_entity*)wr);
|
||||
void *sample = ddsi_sertopic_alloc_sample (topic->m_stopic);
|
||||
struct ddsi_tkmap_instance *tk;
|
||||
if (asleep) {
|
||||
thread_state_awake(thr);
|
||||
}
|
||||
if (ddsi_tkmap_get_key (map, topic->m_stopic, handle, sample)) {
|
||||
if ((tk = ddsi_tkmap_find_by_id (gv.m_tkmap, handle)) != NULL) {
|
||||
struct ddsi_sertopic *tp = ((dds_writer*) wr)->m_topic->m_stopic;
|
||||
void *sample = ddsi_sertopic_alloc_sample (tp);
|
||||
ddsi_serdata_topicless_to_sample (tp, tk->m_sample, sample, NULL, NULL);
|
||||
ddsi_tkmap_instance_unref (tk);
|
||||
ret = dds_dispose_impl (wr, sample, handle, timestamp);
|
||||
ddsi_sertopic_free_sample (tp, sample, DDS_FREE_ALL);
|
||||
} else {
|
||||
DDS_ERROR("No instance related with the provided handle is found\n");
|
||||
ret = DDS_ERRNO(DDS_RETCODE_PRECONDITION_NOT_MET);
|
||||
|
@ -402,7 +405,6 @@ dds_dispose_ih_ts(
|
|||
if (asleep) {
|
||||
thread_state_asleep(thr);
|
||||
}
|
||||
ddsi_sertopic_free_sample (topic->m_stopic, sample, DDS_FREE_ALL);
|
||||
dds_writer_unlock(wr);
|
||||
} else {
|
||||
DDS_ERROR("Error occurred on locking writer\n");
|
||||
|
@ -461,14 +463,14 @@ _Pre_satisfies_(entity & DDS_ENTITY_KIND_MASK)
|
|||
dds_return_t
|
||||
dds_instance_get_key(
|
||||
dds_entity_t entity,
|
||||
dds_instance_handle_t inst,
|
||||
dds_instance_handle_t ih,
|
||||
void *data)
|
||||
{
|
||||
struct thread_state1 * const thr = lookup_thread_state();
|
||||
const bool asleep = !vtime_awake_p(thr->vtime);
|
||||
dds_return_t ret;
|
||||
const dds_topic * topic;
|
||||
struct ddsi_tkmap * map = gv.m_tkmap;
|
||||
struct ddsi_tkmap_instance * tk;
|
||||
|
||||
if(data == NULL){
|
||||
DDS_ERROR("Argument data is NULL\n");
|
||||
|
@ -482,11 +484,13 @@ dds_instance_get_key(
|
|||
ret = DDS_ERRNO(DDS_RETCODE_BAD_PARAMETER);
|
||||
goto err;
|
||||
}
|
||||
ddsi_sertopic_zero_sample (topic->m_stopic, data);
|
||||
if (asleep) {
|
||||
thread_state_awake(thr);
|
||||
}
|
||||
if (ddsi_tkmap_get_key (map, topic->m_stopic, inst, data)) {
|
||||
if ((tk = ddsi_tkmap_find_by_id(gv.m_tkmap, ih)) != NULL) {
|
||||
ddsi_sertopic_zero_sample (topic->m_stopic, data);
|
||||
ddsi_serdata_topicless_to_sample (topic->m_stopic, tk->m_sample, data, NULL, NULL);
|
||||
ddsi_tkmap_instance_unref (tk);
|
||||
ret = DDS_RETCODE_OK;
|
||||
} else {
|
||||
DDS_ERROR("No instance related with the provided entity is found\n");
|
||||
|
|
|
@ -36,7 +36,6 @@ struct ddsi_tkmap * ddsi_tkmap_new (void);
|
|||
void ddsi_tkmap_free (_Inout_ _Post_invalid_ struct ddsi_tkmap *tkmap);
|
||||
void ddsi_tkmap_instance_ref (_In_ struct ddsi_tkmap_instance *tk);
|
||||
uint64_t ddsi_tkmap_lookup (_In_ struct ddsi_tkmap *tkmap, _In_ const struct ddsi_serdata *serdata);
|
||||
_Check_return_ bool ddsi_tkmap_get_key (_In_ struct ddsi_tkmap * map, const struct ddsi_sertopic *topic, _In_ uint64_t iid, _Out_ void * sample);
|
||||
_Check_return_ struct ddsi_tkmap_instance * ddsi_tkmap_find(
|
||||
_In_ struct ddsi_serdata * sd,
|
||||
_In_ const bool rd,
|
||||
|
|
|
@ -111,64 +111,32 @@ uint64_t ddsi_tkmap_lookup (_In_ struct ddsi_tkmap * map, _In_ const struct ddsi
|
|||
{
|
||||
struct ddsi_tkmap_instance dummy;
|
||||
struct ddsi_tkmap_instance * tk;
|
||||
assert (vtime_awake_p(lookup_thread_state()->vtime));
|
||||
dummy.m_sample = (struct ddsi_serdata *) sd;
|
||||
tk = ut_chhLookup (map->m_hh, &dummy);
|
||||
return (tk) ? tk->m_iid : DDS_HANDLE_NIL;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const struct ddsi_sertopic *topic;
|
||||
uint64_t m_iid;
|
||||
void * m_sample;
|
||||
bool m_ret;
|
||||
}
|
||||
tkmap_get_key_arg;
|
||||
|
||||
static void dds_tkmap_get_key_fn (void * vtk, void * varg)
|
||||
{
|
||||
struct ddsi_tkmap_instance * tk = vtk;
|
||||
tkmap_get_key_arg * arg = (tkmap_get_key_arg*) varg;
|
||||
if (tk->m_iid == arg->m_iid)
|
||||
{
|
||||
ddsi_serdata_topicless_to_sample (arg->topic, tk->m_sample, arg->m_sample, 0, 0);
|
||||
arg->m_ret = true;
|
||||
}
|
||||
}
|
||||
|
||||
_Check_return_
|
||||
bool ddsi_tkmap_get_key (_In_ struct ddsi_tkmap * map, const struct ddsi_sertopic *topic, _In_ uint64_t iid, _Out_ void * sample)
|
||||
{
|
||||
tkmap_get_key_arg arg = { topic, iid, sample, false };
|
||||
os_mutexLock (&map->m_lock);
|
||||
ut_chhEnumUnsafe (map->m_hh, dds_tkmap_get_key_fn, &arg);
|
||||
os_mutexUnlock (&map->m_lock);
|
||||
return arg.m_ret;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint64_t m_iid;
|
||||
struct ddsi_tkmap_instance * m_inst;
|
||||
}
|
||||
tkmap_get_inst_arg;
|
||||
|
||||
static void dds_tkmap_get_inst_fn (void * vtk, void * varg)
|
||||
{
|
||||
struct ddsi_tkmap_instance * tk = vtk;
|
||||
tkmap_get_inst_arg * arg = (tkmap_get_inst_arg*) varg;
|
||||
if (tk->m_iid == arg->m_iid)
|
||||
{
|
||||
arg->m_inst = tk;
|
||||
}
|
||||
}
|
||||
|
||||
_Check_return_
|
||||
struct ddsi_tkmap_instance *ddsi_tkmap_find_by_id (_In_ struct ddsi_tkmap *map, _In_ uint64_t iid)
|
||||
{
|
||||
tkmap_get_inst_arg arg = { iid, NULL };
|
||||
ut_chhEnumUnsafe (map->m_hh, dds_tkmap_get_inst_fn, &arg);
|
||||
return arg.m_inst;
|
||||
/* This is not a function that should be used liberally, as it linearly scans the key-to-iid map. */
|
||||
struct ut_chhIter it;
|
||||
struct ddsi_tkmap_instance *tk;
|
||||
uint32_t refc;
|
||||
assert (vtime_awake_p(lookup_thread_state()->vtime));
|
||||
for (tk = ut_chhIterFirst (map->m_hh, &it); tk; tk = ut_chhIterNext (&it))
|
||||
if (tk->m_iid == iid)
|
||||
break;
|
||||
if (tk == NULL)
|
||||
/* Common case of it not existing at all */
|
||||
return NULL;
|
||||
else if (!((refc = os_atomic_ld32 (&tk->m_refc)) & REFC_DELETE) && os_atomic_cas32 (&tk->m_refc, refc, refc+1))
|
||||
/* Common case of it existing, not in the process of being deleted and no one else concurrently modifying the refcount */
|
||||
return tk;
|
||||
else
|
||||
/* Let key value lookup handle the possible CAS loop and the complicated cases */
|
||||
return ddsi_tkmap_find (tk->m_sample, false, false);
|
||||
}
|
||||
|
||||
/* Debug keyhash generation for debug and coverage builds */
|
||||
|
@ -193,6 +161,7 @@ struct ddsi_tkmap_instance * ddsi_tkmap_find(
|
|||
struct ddsi_tkmap_instance * tk;
|
||||
struct ddsi_tkmap * map = gv.m_tkmap;
|
||||
|
||||
assert (vtime_awake_p(lookup_thread_state()->vtime));
|
||||
dummy.m_sample = sd;
|
||||
retry:
|
||||
if ((tk = ut_chhLookup(map->m_hh, &dummy)) != NULL)
|
||||
|
@ -242,7 +211,6 @@ retry:
|
|||
_Check_return_
|
||||
struct ddsi_tkmap_instance * ddsi_tkmap_lookup_instance_ref (_In_ struct ddsi_serdata * sd)
|
||||
{
|
||||
assert (vtime_awake_p (lookup_thread_state ()->vtime));
|
||||
return ddsi_tkmap_find (sd, true, true);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue