efl/io: fix race condition with child model deletion

Summary:
if an event is emitted for a child that is added to the model during a
call to _efl_io_model_children_list(), it's possible that this child
will never be detected by the model's monitor/sentry if it is deleted
before the monitor can detect it, which means there will never be a
corresponding eio event emitted

in this case, ensure that we manually remove this child from the model
since we know we've just deleted it

this fixes reliability issues with efl io model monitor unit test

@fix

Reviewers: cedric

Reviewed By: cedric

Subscribers: #reviewers, #committers

Tags: #efl

Differential Revision: https://phab.enlightenment.org/D9708
This commit is contained in:
Mike Blumenkrantz 2019-08-23 13:21:58 -04:00
parent 7bf8235409
commit 39f978675a
1 changed files with 25 additions and 18 deletions

View File

@ -154,37 +154,25 @@ _efl_model_evt_added_ecore_cb(void *data, int type, void *event)
return EINA_TRUE;
}
static Eina_Bool
_efl_model_evt_deleted_ecore_cb(void *data, int type, void *event)
static void
_model_child_remove(Efl_Io_Model_Data *pd, Eina_Stringshare *path)
{
Efl_Io_Model_Info *mi;
Eina_List *l;
Eio_Monitor_Event *ev = event;
Efl_Io_Model *obj;
Efl_Io_Model_Data *pd = data;
Eina_Stringshare *spath = NULL;
Efl_Io_Model *obj = pd->self;
Efl_Model_Children_Event cevt = { 0 };
unsigned int i = 0;
if (type != EIO_MONITOR_DIRECTORY_DELETED && type != EIO_MONITOR_FILE_DELETED)
return EINA_TRUE;
if (ev->monitor != pd->monitor) return EINA_TRUE;
obj = pd->self;
spath = eina_stringshare_add(ev->filename);
// FIXME: Linear search is pretty slow
EINA_LIST_FOREACH(pd->files, l, mi)
{
if (mi->path == spath)
if (mi->path == path)
break ;
++i;
}
if (i >= eina_list_count(pd->files))
goto end;
return;
cevt.index = i;
cevt.child = mi->object;
@ -197,8 +185,22 @@ _efl_model_evt_deleted_ecore_cb(void *data, int type, void *event)
// This will only trigger the data destruction if no object is referencing them.
_efl_io_model_info_free(mi, EINA_FALSE);
}
end:
static Eina_Bool
_efl_model_evt_deleted_ecore_cb(void *data, int type, void *event)
{
Eio_Monitor_Event *ev = event;
Efl_Io_Model_Data *pd = data;
Eina_Stringshare *spath = NULL;
if (type != EIO_MONITOR_DIRECTORY_DELETED && type != EIO_MONITOR_FILE_DELETED)
return EINA_TRUE;
if (ev->monitor != pd->monitor) return EINA_TRUE;
spath = eina_stringshare_add(ev->filename);
_model_child_remove(pd, spath);
eina_stringshare_del(spath);
return EINA_TRUE;
@ -221,7 +223,12 @@ static void
_eio_done_unlink_cb(void *data, Eio_File *handler EINA_UNUSED)
{
Efl_Io_Model *child = data;
Efl_Io_Model_Data *child_pd, *pd;
child_pd = efl_data_scope_get(child, MY_CLASS);
pd = efl_data_scope_get(efl_parent_get(child), MY_CLASS);
_model_child_remove(pd, child_pd->path);
_eio_del_cleanup(child);
}