mi->name_start = eina_stringshare_strlen(pd->path) + 1;
mi->name_length = mi->path_length - mi->name_start;
mi->type = EINA_FILE_UNKNOWN;
- mi->parent_ref = EINA_TRUE;
+ mi->parent_ref = EINA_FALSE;
+ mi->child_ref = EINA_TRUE;
// Honor filter on new added file too
if (pd->filter.cb)
if (!pd->filter.cb(pd->filter.data, obj, &info))
{
- eina_stringshare_del(mi->path);
+ eina_stringshare_replace(&mi->path, NULL);
free(mi);
goto end;
}
// Remove the entry from the files list
pd->files = eina_list_remove_list(pd->files, l);
- // This should trigger the object child destruction if it exist
- // resulting in the potential destruction of the child, after
- // this point mi and info might be freed.
+ // This will only trigger the data destruction if no object is referencing them.
_efl_io_model_info_free(mi, EINA_FALSE);
end:
if (!model)
{
- if (!info->object)
- {
- efl_del(info->object);
- info->object = NULL;
- }
info->child_ref = EINA_FALSE;
}
else
info->parent_ref)
return ;
- eina_stringshare_del(info->path);
+ eina_stringshare_replace(&info->path, NULL);
free(info);
}
Efl_Io_Model *model = data;
Efl_Io_Model *parent;
- efl_ref(model);
+ efl_ref(model); // For st_done
_eio_build_st_done(data, handler, stat);
parent = efl_parent_get(model);
efl_model_child_del(parent, model);
- efl_unref(model);
+ efl_unref(model); // From the async thread early ref
}
static void
_eio_build_st_error_clobber(void *data, Eio_File *handler, int error)
{
Efl_Io_Model *model = data;
- Efl_Io_Model *parent;
- efl_ref(model);
+ efl_ref(model); // For st_error unref
_eio_build_st_error(data, handler, error);
- parent = efl_parent_get(model);
- efl_model_child_del(parent, model);
- efl_unref(model);
+ efl_unref(model); // From the async thread early ref
}
static void
if (pd->request.stat) return ;
if (pd->error) return ;
- pd->request.stat = eio_file_direct_stat(pd->path, _eio_build_st_done, _eio_build_st_error, efl_ref(model));
+ pd->request.stat = eio_file_direct_stat(pd->path,
+ _eio_build_st_done,
+ _eio_build_st_error,
+ efl_ref(model));
}
static void
static Eina_Value *
_property_path_cb(const Eo *obj EINA_UNUSED, Efl_Io_Model_Data *pd)
{
- return eina_value_string_new(pd->path);
+ return eina_value_stringshare_new(pd->path);
}
static Eina_Value *
}
else
{
- f = efl_loop_future_resolved(obj, eina_value_string_init(pd->path));
+ f = efl_loop_future_resolved(obj, eina_value_stringshare_init(pd->path));
}
return f;
mi->name_start = info->name_start;
mi->name_length = info->name_length;
mi->type = _efl_io_model_info_type_get(info, NULL);
- mi->parent_ref = EINA_TRUE;
+ mi->parent_ref = EINA_FALSE;
+ mi->child_ref = EINA_TRUE;
cevt.index = eina_list_count(pd->files);
cevt.child = NULL;
}
static Eina_Value
-_efl_io_model_children_list_on(void *data, const Eina_Value v,
- const Eina_Future *dead EINA_UNUSED)
+_efl_io_model_children_list_on(Eo *o EINA_UNUSED, void *data, const Eina_Value v)
{
Efl_Io_Model_Data *pd = data;
- pd->request.listing = NULL;
- pd->listed = EINA_TRUE;
-
// Now that we have listed the content of the directory,
// we can whatch over it
_efl_io_model_efl_model_monitor_add(pd);
return v;
}
+static void
+_efl_io_model_children_list_cleanup(Eo *o EINA_UNUSED, void *data, const Eina_Future *dead_future EINA_UNUSED)
+{
+ Efl_Io_Model_Data *pd = data;
+
+ pd->request.listing = NULL;
+ pd->listed = EINA_TRUE;
+}
+
/**
* Children Count Get
*/
f = efl_io_manager_direct_ls(iom, pd->path, EINA_FALSE,
(void*) obj, _efl_io_model_children_list, NULL);
- f = eina_future_then(f, _efl_io_model_children_list_on, pd, NULL);
- pd->request.listing = efl_future_then(obj, f);
+
+ pd->request.listing = efl_future_then(obj, f,
+ .success = _efl_io_model_children_list_on,
+ .free = _efl_io_model_children_list_cleanup,
+ .data = pd);
}
return eina_list_count(pd->files);
Eina_File_Type type;
child_pd = efl_data_scope_get(child, MY_CLASS);
- if (!child_pd->info) goto on_error;
- if (child_pd->error) goto on_error;
+ if (!child_pd->info) return;
+ if (child_pd->error) return;
type = child_pd->info->type;
return ;
}
+ // Already in progress
+ if (child_pd->request.del) return;
+
efl_ref(child);
if (type == EINA_FILE_DIR)
{
_eio_error_unlink_cb,
child);
}
-
- return ;
-
- on_error:
- efl_del(child);
}
/**
Efl_Io_Model_Info *info = eina_list_data_get(ls);
Efl_Io_Model_Data *child_data = NULL;
- info->child_ref = EINA_TRUE;
+ info->parent_ref = EINA_TRUE;
if (info->object == NULL)
// Little trick here, setting internal data before finalize
- info->object = efl_add(EFL_IO_MODEL_CLASS, obj,
- child_data = efl_data_scope_get(efl_added, EFL_IO_MODEL_CLASS),
- child_data->info = info,
- child_data->path = eina_stringshare_ref(info->path),
- child_data->parent = ls,
- // NOTE: We are assuming here that the parent model will outlive all its children
- child_data->filter.cb = pd->filter.cb,
- child_data->filter.data = pd->filter.data);
+ info->object = efl_add_ref(EFL_IO_MODEL_CLASS, obj,
+ efl_loop_model_volatile_make(efl_added),
+ child_data = efl_data_scope_get(efl_added, EFL_IO_MODEL_CLASS),
+ child_data->info = info,
+ child_data->path = eina_stringshare_ref(info->path),
+ child_data->parent = ls,
+ // NOTE: We are assuming here that the parent model will outlive all its children
+ child_data->filter.cb = pd->filter.cb,
+ child_data->filter.data = pd->filter.data);
eina_value_array_append(&array, info->object);
+ efl_wref_add(info->object, &info->object);
+ efl_unref(info->object);
+
count--;
ls = eina_list_next(ls);
}
{
Efl_Io_Model_Info *info;
+
+ free(priv->st);
+ priv->st = NULL;
+
_efl_io_model_info_free(priv->info, EINA_TRUE);
priv->info = NULL;
EINA_LIST_FREE(priv->files, info)
_efl_io_model_info_free(info, EINA_FALSE);
- eina_stringshare_del(priv->path);
+ eina_stringshare_replace(&priv->path, NULL);
efl_destructor(efl_super(obj, MY_CLASS));
}
static void
_efl_io_model_efl_object_invalidate(Eo *obj , Efl_Io_Model_Data *priv)
{
+ // This has to be done first, to make sure that the automatic
+ // del is not done anymore. Or it would lead to too much
+ // unref when stopping async thread (During invalidate, we
+ // are already in the process of doing an implicit del).
+ efl_invalidate(efl_super(obj, EFL_IO_MODEL_CLASS));
+
_efl_io_model_efl_model_monitor_del(priv);
// Unlink the object from the parent
- if (priv->info) priv->info->object = NULL;
+ if (priv->info)
+ {
+ efl_wref_del(priv->info->object, &priv->info->object);
+ priv->info->object = NULL;
+ }
if (priv->request.del)
{
if (!ecore_thread_wait(priv->request.del->thread, 0.1))
ecore_thread_wait(priv->request.stat->thread, 0.1);
}
}
-
- efl_invalidate(efl_super(obj, EFL_IO_MODEL_CLASS));
}
#include "efl_io_model.eo.c"
const char* tmpdir = NULL;
Eina_Bool children_deleted = EINA_FALSE;
+// This will ensure that the child have the time to be automatically destroyed
+static Eina_Value
+_delayed_quit(Eo *o EINA_UNUSED, void *data EINA_UNUSED, const Eina_Value v)
+{
+ ecore_main_loop_quit();
+
+ return v;
+}
+
+static Eina_Value
+_children_got(Eo *o, void *data EINA_UNUSED, const Eina_Value v)
+{
+ Eo *child = NULL;
+ unsigned int i, len;
+ Eina_Value r = (Eina_Value) v;
+
+ EINA_VALUE_ARRAY_FOREACH(&v, len, i, child)
+ {
+ Eina_Value *path;
+ char *str;
+
+ path = efl_model_property_get(child, "path");
+ fail_if(path == NULL);
+ str = eina_value_to_string(path);
+ fail_if(str == NULL);
+
+ if (temp_filename && strcmp(str, temp_filename) == 0)
+ r = eina_future_as_value(efl_future_then(efl_loop_get(o),
+ efl_loop_job(efl_loop_get(o)),
+ .success = _delayed_quit));
+
+
+ free(str);
+ eina_value_free(path);
+ }
+
+ return r;
+}
+
+static Eina_Value
+_children_failed(Eo *o EINA_UNUSED, void *data EINA_UNUSED, const Eina_Error err)
+{
+ ck_abort_msg( "Failed to get the child with '%s'.\n", eina_error_msg_get(err));
+ return eina_value_error_init(err);
+}
+
static void
_children_removed_cb(void *data EINA_UNUSED, const Efl_Event* event)
{
Eina_Value *path;
char *str;
+ if (!evt->child)
+ {
+ Eina_Future *f;
+
+ // Last time we can fetch the object
+ f = efl_future_then(event->object,
+ efl_model_children_slice_get(event->object, evt->index, 1),
+ .success = _children_got,
+ .error = _children_failed,
+ .success_type = EINA_VALUE_TYPE_ARRAY);
+ fail_if(f == NULL);
+ return;
+ }
+
fail_if(evt->child == NULL);
path = efl_model_property_get(evt->child, "path");
fail_if(path == NULL);
fail_if(str == NULL);
if (temp_filename && strcmp(str, temp_filename) == 0)
- ecore_main_loop_quit();
+ efl_future_then(efl_loop_get(evt->child),
+ efl_loop_job(efl_loop_get(evt->child)),
+ .success = _delayed_quit);
free(str);
eina_value_free(path);