summaryrefslogtreecommitdiff
path: root/src/lib/eio
diff options
context:
space:
mode:
authorCedric BAIL <cedric.bail@free.fr>2019-02-23 08:57:19 -0500
committerMike Blumenkrantz <zmike@samsung.com>2019-02-23 08:57:48 -0500
commit301b05502cff4125633da25e46d5cf0dccd1565a (patch)
tree9b4cbd3387bd193872cbf3497d8fb28c41407218 /src/lib/eio
parent790fc1b8c5ce819dc7e17063baad52968b0c6706 (diff)
eio: enforce proper lifecycle for all Efl.Io_Model and fix discovered lifecycle bugs.
Summary: This make sure that the object returned by children_slice_get are properly destroyed when the refcount drop to only the parent holding a reference on it. This make it clear that the user of the api can rely on efl_ref/efl_unref to actually manage its use of the returned object. Additionnaly we are cleaning up the created object that we are using to build our own request inside the Efl.Io.Model and avoid internal leak. Depends on D7864 Reviewers: felipealmeida, segfaultxavi, SanghyeonLee, zmike, bu5hm4n Reviewed By: zmike Subscribers: #reviewers, #committers Tags: #efl Maniphest Tasks: T7528 Differential Revision: https://phab.enlightenment.org/D7865
Diffstat (limited to 'src/lib/eio')
-rw-r--r--src/lib/eio/efl_io_model.c115
1 files changed, 66 insertions, 49 deletions
diff --git a/src/lib/eio/efl_io_model.c b/src/lib/eio/efl_io_model.c
index 76cc7ab..bb9bde2 100644
--- a/src/lib/eio/efl_io_model.c
+++ b/src/lib/eio/efl_io_model.c
@@ -100,7 +100,8 @@ _efl_model_evt_added_ecore_cb(void *data, int type, void *event)
100 mi->name_start = eina_stringshare_strlen(pd->path) + 1; 100 mi->name_start = eina_stringshare_strlen(pd->path) + 1;
101 mi->name_length = mi->path_length - mi->name_start; 101 mi->name_length = mi->path_length - mi->name_start;
102 mi->type = EINA_FILE_UNKNOWN; 102 mi->type = EINA_FILE_UNKNOWN;
103 mi->parent_ref = EINA_TRUE; 103 mi->parent_ref = EINA_FALSE;
104 mi->child_ref = EINA_TRUE;
104 105
105 // Honor filter on new added file too 106 // Honor filter on new added file too
106 if (pd->filter.cb) 107 if (pd->filter.cb)
@@ -115,7 +116,7 @@ _efl_model_evt_added_ecore_cb(void *data, int type, void *event)
115 116
116 if (!pd->filter.cb(pd->filter.data, obj, &info)) 117 if (!pd->filter.cb(pd->filter.data, obj, &info))
117 { 118 {
118 eina_stringshare_del(mi->path); 119 eina_stringshare_replace(&mi->path, NULL);
119 free(mi); 120 free(mi);
120 goto end; 121 goto end;
121 } 122 }
@@ -176,9 +177,7 @@ _efl_model_evt_deleted_ecore_cb(void *data, int type, void *event)
176 // Remove the entry from the files list 177 // Remove the entry from the files list
177 pd->files = eina_list_remove_list(pd->files, l); 178 pd->files = eina_list_remove_list(pd->files, l);
178 179
179 // This should trigger the object child destruction if it exist 180 // This will only trigger the data destruction if no object is referencing them.
180 // resulting in the potential destruction of the child, after
181 // this point mi and info might be freed.
182 _efl_io_model_info_free(mi, EINA_FALSE); 181 _efl_io_model_info_free(mi, EINA_FALSE);
183 182
184 end: 183 end:
@@ -225,11 +224,6 @@ _efl_io_model_info_free(Efl_Io_Model_Info *info, Eina_Bool model)
225 224
226 if (!model) 225 if (!model)
227 { 226 {
228 if (!info->object)
229 {
230 efl_del(info->object);
231 info->object = NULL;
232 }
233 info->child_ref = EINA_FALSE; 227 info->child_ref = EINA_FALSE;
234 } 228 }
235 else 229 else
@@ -241,7 +235,7 @@ _efl_io_model_info_free(Efl_Io_Model_Info *info, Eina_Bool model)
241 info->parent_ref) 235 info->parent_ref)
242 return ; 236 return ;
243 237
244 eina_stringshare_del(info->path); 238 eina_stringshare_replace(&info->path, NULL);
245 free(info); 239 free(info);
246} 240}
247 241
@@ -336,11 +330,11 @@ _eio_build_st_done_clobber(void *data, Eio_File *handler, const Eina_Stat *stat)
336 Efl_Io_Model *model = data; 330 Efl_Io_Model *model = data;
337 Efl_Io_Model *parent; 331 Efl_Io_Model *parent;
338 332
339 efl_ref(model); 333 efl_ref(model); // For st_done
340 _eio_build_st_done(data, handler, stat); 334 _eio_build_st_done(data, handler, stat);
341 parent = efl_parent_get(model); 335 parent = efl_parent_get(model);
342 efl_model_child_del(parent, model); 336 efl_model_child_del(parent, model);
343 efl_unref(model); 337 efl_unref(model); // From the async thread early ref
344} 338}
345 339
346static void 340static void
@@ -361,13 +355,10 @@ static void
361_eio_build_st_error_clobber(void *data, Eio_File *handler, int error) 355_eio_build_st_error_clobber(void *data, Eio_File *handler, int error)
362{ 356{
363 Efl_Io_Model *model = data; 357 Efl_Io_Model *model = data;
364 Efl_Io_Model *parent;
365 358
366 efl_ref(model); 359 efl_ref(model); // For st_error unref
367 _eio_build_st_error(data, handler, error); 360 _eio_build_st_error(data, handler, error);
368 parent = efl_parent_get(model); 361 efl_unref(model); // From the async thread early ref
369 efl_model_child_del(parent, model);
370 efl_unref(model);
371} 362}
372 363
373static void 364static void
@@ -377,7 +368,10 @@ _eio_build_st(const Efl_Io_Model *model, Efl_Io_Model_Data *pd)
377 if (pd->request.stat) return ; 368 if (pd->request.stat) return ;
378 if (pd->error) return ; 369 if (pd->error) return ;
379 370
380 pd->request.stat = eio_file_direct_stat(pd->path, _eio_build_st_done, _eio_build_st_error, efl_ref(model)); 371 pd->request.stat = eio_file_direct_stat(pd->path,
372 _eio_build_st_done,
373 _eio_build_st_error,
374 efl_ref(model));
381} 375}
382 376
383static void 377static void
@@ -502,7 +496,7 @@ _property_filename_cb(const Eo *obj, Efl_Io_Model_Data *pd)
502static Eina_Value * 496static Eina_Value *
503_property_path_cb(const Eo *obj EINA_UNUSED, Efl_Io_Model_Data *pd) 497_property_path_cb(const Eo *obj EINA_UNUSED, Efl_Io_Model_Data *pd)
504{ 498{
505 return eina_value_string_new(pd->path); 499 return eina_value_stringshare_new(pd->path);
506} 500}
507 501
508static Eina_Value * 502static Eina_Value *
@@ -700,7 +694,7 @@ _efl_io_model_efl_model_property_set(Eo *obj,
700 } 694 }
701 else 695 else
702 { 696 {
703 f = efl_loop_future_resolved(obj, eina_value_string_init(pd->path)); 697 f = efl_loop_future_resolved(obj, eina_value_stringshare_init(pd->path));
704 } 698 }
705 699
706 return f; 700 return f;
@@ -741,7 +735,8 @@ _efl_io_model_children_list(void *data, Eina_Array *entries)
741 mi->name_start = info->name_start; 735 mi->name_start = info->name_start;
742 mi->name_length = info->name_length; 736 mi->name_length = info->name_length;
743 mi->type = _efl_io_model_info_type_get(info, NULL); 737 mi->type = _efl_io_model_info_type_get(info, NULL);
744 mi->parent_ref = EINA_TRUE; 738 mi->parent_ref = EINA_FALSE;
739 mi->child_ref = EINA_TRUE;
745 740
746 cevt.index = eina_list_count(pd->files); 741 cevt.index = eina_list_count(pd->files);
747 cevt.child = NULL; 742 cevt.child = NULL;
@@ -755,14 +750,10 @@ _efl_io_model_children_list(void *data, Eina_Array *entries)
755} 750}
756 751
757static Eina_Value 752static Eina_Value
758_efl_io_model_children_list_on(void *data, const Eina_Value v, 753_efl_io_model_children_list_on(Eo *o EINA_UNUSED, void *data, const Eina_Value v)
759 const Eina_Future *dead EINA_UNUSED)
760{ 754{
761 Efl_Io_Model_Data *pd = data; 755 Efl_Io_Model_Data *pd = data;
762 756
763 pd->request.listing = NULL;
764 pd->listed = EINA_TRUE;
765
766 // Now that we have listed the content of the directory, 757 // Now that we have listed the content of the directory,
767 // we can whatch over it 758 // we can whatch over it
768 _efl_io_model_efl_model_monitor_add(pd); 759 _efl_io_model_efl_model_monitor_add(pd);
@@ -770,6 +761,15 @@ _efl_io_model_children_list_on(void *data, const Eina_Value v,
770 return v; 761 return v;
771} 762}
772 763
764static void
765_efl_io_model_children_list_cleanup(Eo *o EINA_UNUSED, void *data, const Eina_Future *dead_future EINA_UNUSED)
766{
767 Efl_Io_Model_Data *pd = data;
768
769 pd->request.listing = NULL;
770 pd->listed = EINA_TRUE;
771}
772
773/** 773/**
774 * Children Count Get 774 * Children Count Get
775 */ 775 */
@@ -801,8 +801,11 @@ _efl_io_model_efl_model_children_count_get(const Eo *obj, Efl_Io_Model_Data *pd)
801 801
802 f = efl_io_manager_direct_ls(iom, pd->path, EINA_FALSE, 802 f = efl_io_manager_direct_ls(iom, pd->path, EINA_FALSE,
803 (void*) obj, _efl_io_model_children_list, NULL); 803 (void*) obj, _efl_io_model_children_list, NULL);
804 f = eina_future_then(f, _efl_io_model_children_list_on, pd, NULL); 804
805 pd->request.listing = efl_future_then(obj, f); 805 pd->request.listing = efl_future_then(obj, f,
806 .success = _efl_io_model_children_list_on,
807 .free = _efl_io_model_children_list_cleanup,
808 .data = pd);
806 } 809 }
807 810
808 return eina_list_count(pd->files); 811 return eina_list_count(pd->files);
@@ -878,8 +881,8 @@ _efl_io_model_efl_model_child_del(Eo *obj EINA_UNUSED,
878 Eina_File_Type type; 881 Eina_File_Type type;
879 882
880 child_pd = efl_data_scope_get(child, MY_CLASS); 883 child_pd = efl_data_scope_get(child, MY_CLASS);
881 if (!child_pd->info) goto on_error; 884 if (!child_pd->info) return;
882 if (child_pd->error) goto on_error; 885 if (child_pd->error) return;
883 886
884 type = child_pd->info->type; 887 type = child_pd->info->type;
885 888
@@ -889,6 +892,9 @@ _efl_io_model_efl_model_child_del(Eo *obj EINA_UNUSED,
889 return ; 892 return ;
890 } 893 }
891 894
895 // Already in progress
896 if (child_pd->request.del) return;
897
892 efl_ref(child); 898 efl_ref(child);
893 if (type == EINA_FILE_DIR) 899 if (type == EINA_FILE_DIR)
894 { 900 {
@@ -906,11 +912,6 @@ _efl_io_model_efl_model_child_del(Eo *obj EINA_UNUSED,
906 _eio_error_unlink_cb, 912 _eio_error_unlink_cb,
907 child); 913 child);
908 } 914 }
909
910 return ;
911
912 on_error:
913 efl_del(child);
914} 915}
915 916
916/** 917/**
@@ -947,20 +948,24 @@ _efl_io_model_efl_model_children_slice_get(Eo *obj, Efl_Io_Model_Data *pd,
947 Efl_Io_Model_Info *info = eina_list_data_get(ls); 948 Efl_Io_Model_Info *info = eina_list_data_get(ls);
948 Efl_Io_Model_Data *child_data = NULL; 949 Efl_Io_Model_Data *child_data = NULL;
949 950
950 info->child_ref = EINA_TRUE; 951 info->parent_ref = EINA_TRUE;
951 952
952 if (info->object == NULL) 953 if (info->object == NULL)
953 // Little trick here, setting internal data before finalize 954 // Little trick here, setting internal data before finalize
954 info->object = efl_add(EFL_IO_MODEL_CLASS, obj, 955 info->object = efl_add_ref(EFL_IO_MODEL_CLASS, obj,
955 child_data = efl_data_scope_get(efl_added, EFL_IO_MODEL_CLASS), 956 efl_loop_model_volatile_make(efl_added),
956 child_data->info = info, 957 child_data = efl_data_scope_get(efl_added, EFL_IO_MODEL_CLASS),
957 child_data->path = eina_stringshare_ref(info->path), 958 child_data->info = info,
958 child_data->parent = ls, 959 child_data->path = eina_stringshare_ref(info->path),
959 // NOTE: We are assuming here that the parent model will outlive all its children 960 child_data->parent = ls,
960 child_data->filter.cb = pd->filter.cb, 961 // NOTE: We are assuming here that the parent model will outlive all its children
961 child_data->filter.data = pd->filter.data); 962 child_data->filter.cb = pd->filter.cb,
963 child_data->filter.data = pd->filter.data);
962 eina_value_array_append(&array, info->object); 964 eina_value_array_append(&array, info->object);
963 965
966 efl_wref_add(info->object, &info->object);
967 efl_unref(info->object);
968
964 count--; 969 count--;
965 ls = eina_list_next(ls); 970 ls = eina_list_next(ls);
966 } 971 }
@@ -1017,13 +1022,17 @@ _efl_io_model_efl_object_destructor(Eo *obj , Efl_Io_Model_Data *priv)
1017{ 1022{
1018 Efl_Io_Model_Info *info; 1023 Efl_Io_Model_Info *info;
1019 1024
1025
1026 free(priv->st);
1027 priv->st = NULL;
1028
1020 _efl_io_model_info_free(priv->info, EINA_TRUE); 1029 _efl_io_model_info_free(priv->info, EINA_TRUE);
1021 priv->info = NULL; 1030 priv->info = NULL;
1022 1031
1023 EINA_LIST_FREE(priv->files, info) 1032 EINA_LIST_FREE(priv->files, info)
1024 _efl_io_model_info_free(info, EINA_FALSE); 1033 _efl_io_model_info_free(info, EINA_FALSE);
1025 1034
1026 eina_stringshare_del(priv->path); 1035 eina_stringshare_replace(&priv->path, NULL);
1027 1036
1028 efl_destructor(efl_super(obj, MY_CLASS)); 1037 efl_destructor(efl_super(obj, MY_CLASS));
1029} 1038}
@@ -1031,10 +1040,20 @@ _efl_io_model_efl_object_destructor(Eo *obj , Efl_Io_Model_Data *priv)
1031static void 1040static void
1032_efl_io_model_efl_object_invalidate(Eo *obj , Efl_Io_Model_Data *priv) 1041_efl_io_model_efl_object_invalidate(Eo *obj , Efl_Io_Model_Data *priv)
1033{ 1042{
1043 // This has to be done first, to make sure that the automatic
1044 // del is not done anymore. Or it would lead to too much
1045 // unref when stopping async thread (During invalidate, we
1046 // are already in the process of doing an implicit del).
1047 efl_invalidate(efl_super(obj, EFL_IO_MODEL_CLASS));
1048
1034 _efl_io_model_efl_model_monitor_del(priv); 1049 _efl_io_model_efl_model_monitor_del(priv);
1035 1050
1036 // Unlink the object from the parent 1051 // Unlink the object from the parent
1037 if (priv->info) priv->info->object = NULL; 1052 if (priv->info)
1053 {
1054 efl_wref_del(priv->info->object, &priv->info->object);
1055 priv->info->object = NULL;
1056 }
1038 if (priv->request.del) 1057 if (priv->request.del)
1039 { 1058 {
1040 if (!ecore_thread_wait(priv->request.del->thread, 0.1)) 1059 if (!ecore_thread_wait(priv->request.del->thread, 0.1))
@@ -1059,8 +1078,6 @@ _efl_io_model_efl_object_invalidate(Eo *obj , Efl_Io_Model_Data *priv)
1059 ecore_thread_wait(priv->request.stat->thread, 0.1); 1078 ecore_thread_wait(priv->request.stat->thread, 0.1);
1060 } 1079 }
1061 } 1080 }
1062
1063 efl_invalidate(efl_super(obj, EFL_IO_MODEL_CLASS));
1064} 1081}
1065 1082
1066#include "efl_io_model.eo.c" 1083#include "efl_io_model.eo.c"