path: root/src/lib/efl_mono
diff options
authorVitor Sousa <>2019-05-31 17:43:11 -0300
committerVitor Sousa <>2019-05-31 17:44:12 -0300
commitfcf5f1d2e2d9ce877d550dd3352bbd6e0527299e (patch)
tree419d1e22dddf6d9283ce05cd92817df1a6371fa9 /src/lib/efl_mono
parent937da0b12c5b2b07a173199078856c35becdb0e0 (diff)
csharp: Refactor wrapper lifetime.
Summary: This commit makes use of the `ownership,shared` and `ownership,unique` events from Efl.Object in order to avoid the C# wrapper from being collected while C code holds a reference to the object. For example, creating a list of items in a for loop and attaching events to them would fails without this commit, as the C# GC may collect the wrapper. The basic idea is that we use a `WrapperSupervisor`, which is stored in the Eo data storage, with a GCHandle allocated for the lifetime of the underlying Eo object. This supervisor takes care of holding either a weak C# reference (when in unique mode, allowing the wrapper to be GC'd) or a hard C# reference (when in shared mode, making the wrapper non-collectable while the Eo has extra references). One limitation is that object graphs can leak if a shared object in the graph - an Eo child for example - stores a hard reference to another object in the graph as a C# field. In this example, this causes the parent to always have a hard C# reference (from the child) as the child is non-collectable due to the parent holding an Eo reference to it. Depends on D8678 Test Plan: `ninja test` and `make test` Reviewers: lauromoura, felipealmeida, woohyun, segfaultxavi Reviewed By: lauromoura Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision:
Diffstat (limited to 'src/lib/efl_mono')
1 files changed, 19 insertions, 24 deletions
diff --git a/src/lib/efl_mono/efl_custom_exports_mono.c b/src/lib/efl_mono/efl_custom_exports_mono.c
index c4a3b54bc5..55f0054da0 100644
--- a/src/lib/efl_mono/efl_custom_exports_mono.c
+++ b/src/lib/efl_mono/efl_custom_exports_mono.c
@@ -23,44 +23,39 @@
23# endif 23# endif
24#endif /* ! _WIN32 */ 24#endif /* ! _WIN32 */
25 25
26typedef void (*Efl_Mono_Free_GCHandle_Cb)(void *gchandle);
27typedef void (*Efl_Mono_Remove_Events_Cb)(Eo *obj, void *gchandle);
28 26
29static Efl_Mono_Free_GCHandle_Cb _efl_mono_free_gchandle_call = NULL; 27EAPI const char *efl_mono_wrapper_supervisor_key_get()
30static Efl_Mono_Remove_Events_Cb _efl_mono_remove_events_call = NULL; 28{
29 return "__c#_wrapper_supervisor";
31 31
32EAPI void efl_mono_gchandle_callbacks_set(Efl_Mono_Free_GCHandle_Cb free_gchandle_cb, Efl_Mono_Remove_Events_Cb remove_events_cb) 32EAPI void *efl_mono_wrapper_supervisor_get(Eo *eo)
33{ 33{
34 _efl_mono_free_gchandle_call = free_gchandle_cb; 34 return efl_key_data_get(eo, efl_mono_wrapper_supervisor_key_get());
35 _efl_mono_remove_events_call = remove_events_cb;
36} 35}
37 36
38EAPI void efl_mono_native_dispose(Eo *obj, void* gchandle) 37EAPI void efl_mono_wrapper_supervisor_set(Eo *eo, void *ws)
39{ 38{
40 if (gchandle) _efl_mono_remove_events_call(obj, gchandle); 39 efl_key_data_set(eo, efl_mono_wrapper_supervisor_key_get(), ws);
41 efl_unref(obj);
42 if (gchandle) _efl_mono_free_gchandle_call(gchandle);
43} 40}
44 41
45typedef struct _Efl_Mono_Native_Dispose_Data 42typedef void (*Efl_Mono_Free_Wrapper_Supervisor_Cb)(Eo *obj);
44static Efl_Mono_Free_Wrapper_Supervisor_Cb _efl_mono_free_wrapper_supervisor_call = NULL;
46EAPI void efl_mono_wrapper_supervisor_callbacks_set(Efl_Mono_Free_Wrapper_Supervisor_Cb free_wrapper_supervisor_cb)
46{ 47{
47 Eo *obj; 48 _efl_mono_free_wrapper_supervisor_call = free_wrapper_supervisor_cb;
48 void *gchandle; 49}
49} Efl_Mono_Native_Dispose_Data;
50 50
51static void _efl_mono_native_dispose_cb(void *data) 51EAPI void efl_mono_native_dispose(Eo *obj)
52{ 52{
53 Efl_Mono_Native_Dispose_Data *dd = data; 53 _efl_mono_free_wrapper_supervisor_call(obj);
54 efl_mono_native_dispose(dd->obj, dd->gchandle);
55 free(dd);
56} 54}
57 55
58EAPI void efl_mono_thread_safe_native_dispose(Eo *obj, void* gchandle) 56EAPI void efl_mono_thread_safe_native_dispose(Eo *obj)
59{ 57{
60 Efl_Mono_Native_Dispose_Data *dd = malloc(sizeof(Efl_Mono_Native_Dispose_Data)); 58 ecore_main_loop_thread_safe_call_async((Ecore_Cb)efl_mono_native_dispose, obj);
61 dd->obj = obj;
62 dd->gchandle = gchandle;
63 ecore_main_loop_thread_safe_call_async(_efl_mono_native_dispose_cb, dd);
64} 59}
65 60
66static void _efl_mono_unref_cb(void *obj) 61static void _efl_mono_unref_cb(void *obj)