summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLauro Moura <lauromoura@expertisesolutions.com.br>2019-12-03 08:52:14 -0300
committerLauro Moura <lauromoura@expertisesolutions.com.br>2019-12-16 18:48:52 -0300
commit9b3ed6ace5dd92d37994b736acbacfdb1baeb5bf (patch)
tree7749c83ee2e4cedbb0d81df3d47550c2a5dbbc28
parentd2f849a7a4dcfceefe4413f3e82c05355c706664 (diff)
WIP csharp: Fix passing acessor with ownershipdevs/lauromoura/T8486-csharp-collections
When passing an owned acessor from a converted collection we need a way to unpin the passed data when the accessor is freed. This commits adds a thin wrapper around the CArray accessor that unpins the data when freed. NOTE: Needs to update the test after D10878 commented out the accessor indexer
-rw-r--r--src/bindings/mono/efl_mono/meson.build1
-rw-r--r--src/bindings/mono/eina_mono/eina_accessor.cs6
-rw-r--r--src/bindings/mono/eo_mono/iwrapper.cs39
-rw-r--r--src/lib/efl_mono/efl_mono_accessors.c93
-rw-r--r--src/tests/efl_mono/Eo.cs36
-rw-r--r--src/tests/efl_mono/dummy_test_object.c17
-rw-r--r--src/tests/efl_mono/dummy_test_object.eo7
7 files changed, 185 insertions, 14 deletions
diff --git a/src/bindings/mono/efl_mono/meson.build b/src/bindings/mono/efl_mono/meson.build
index e93d323..165b6d5 100644
--- a/src/bindings/mono/efl_mono/meson.build
+++ b/src/bindings/mono/efl_mono/meson.build
@@ -83,6 +83,7 @@ endforeach
83efl_mono_lib = library('eflcustomexportsmono', 83efl_mono_lib = library('eflcustomexportsmono',
84 [ 84 [
85 join_paths('..', '..', '..', 'lib', 'efl_mono', 'efl_custom_exports_mono.c'), 85 join_paths('..', '..', '..', 'lib', 'efl_mono', 'efl_custom_exports_mono.c'),
86 join_paths('..', '..', '..', 'lib', 'efl_mono', 'efl_mono_accessors.c'),
86 join_paths('..', '..', '..', 'lib', 'efl_mono', 'efl_mono_model_internal.c'), 87 join_paths('..', '..', '..', 'lib', 'efl_mono', 'efl_mono_model_internal.c'),
87 ], 88 ],
88 pub_eo_file_target, 89 pub_eo_file_target,
diff --git a/src/bindings/mono/eina_mono/eina_accessor.cs b/src/bindings/mono/eina_mono/eina_accessor.cs
index 7c8b52c..50e9f69 100644
--- a/src/bindings/mono/eina_mono/eina_accessor.cs
+++ b/src/bindings/mono/eina_mono/eina_accessor.cs
@@ -34,6 +34,12 @@ internal class AccessorNativeFunctions
34 eina_accessor_data_get(IntPtr accessor, uint position, out IntPtr data); 34 eina_accessor_data_get(IntPtr accessor, uint position, out IntPtr data);
35 [DllImport(efl.Libs.Eina)] public static extern void 35 [DllImport(efl.Libs.Eina)] public static extern void
36 eina_accessor_free(IntPtr accessor); 36 eina_accessor_free(IntPtr accessor);
37 [DllImport(efl.Libs.CustomExports)] public static extern IntPtr
38 eina_mono_owned_carray_length_accessor_new(IntPtr array,
39 uint step,
40 uint length,
41 Eina.Callbacks.EinaFreeCb freeCb,
42 IntPtr handle);
37} 43}
38 44
39/// <summary>Accessors provide an uniform way of accessing Eina containers, 45/// <summary>Accessors provide an uniform way of accessing Eina containers,
diff --git a/src/bindings/mono/eo_mono/iwrapper.cs b/src/bindings/mono/eo_mono/iwrapper.cs
index e761935..421ce18 100644
--- a/src/bindings/mono/eo_mono/iwrapper.cs
+++ b/src/bindings/mono/eo_mono/iwrapper.cs
@@ -790,21 +790,44 @@ public static class Globals
790 return wrappedAccessor.Handle; 790 return wrappedAccessor.Handle;
791 } 791 }
792 792
793 var list = new List<IntPtr>(); 793 // TODO: Check if we're either an Eina.List or Eina.Collection?
794 // We could just rewrap their native accessors
795 IntPtr[] intPtrs = new IntPtr[enumerable.Count()];
796
797 int i = 0;
794 foreach (T data in enumerable) 798 foreach (T data in enumerable)
795 { 799 {
796 list.Add(Eina.TraitFunctions.ManagedToNativeAlloc<T>(data)); 800 intPtrs[i] = Eina.TraitFunctions.ManagedToNativeAlloc<T>(data);
801 i++;
797 } 802 }
798 IntPtr[] dataArray = list.ToArray();
799 GCHandle pinnedArray = GCHandle.Alloc(dataArray, GCHandleType.Pinned); //FIXME: Need to free.
800 IntPtr ret = Eina.AccessorNativeFunctions.eina_carray_length_accessor_new(pinnedArray.AddrOfPinnedObject(), (uint)(IntPtr.Size), (uint)dataArray.Length);
801 803
802 if (!isMoved) 804 IntPtr[] dataArray = intPtrs.ToArray();
805 GCHandle pinnedArray = GCHandle.Alloc(dataArray, GCHandleType.Pinned);
806
807 IntPtr nativeAccessor = IntPtr.Zero;
808
809 if (isMoved)
803 { 810 {
804 // FIXME Need to free ret and unpin pinnedArray in the future. 811 // We need a custom accessor that would unpin the data when freed.
812 nativeAccessor = Eina.AccessorNativeFunctions.eina_mono_owned_carray_length_accessor_new(pinnedArray.AddrOfPinnedObject(),
813 (uint)IntPtr.Size,
814 (uint)dataArray.Length,
815 free_gchandle,
816 GCHandle.ToIntPtr(pinnedArray));
817 }
818 else
819 {
820 // FIXME: Leaking....
821 nativeAccessor = Eina.AccessorNativeFunctions.eina_carray_length_accessor_new(pinnedArray.AddrOfPinnedObject(), (uint)(IntPtr.Size), (uint)dataArray.Length);
805 } 822 }
806 823
807 return ret; 824 if (nativeAccessor == IntPtr.Zero)
825 {
826 pinnedArray.Free();
827 throw new InvalidOperationException("Failed to get native accessor for the given container");
828 }
829
830 return nativeAccessor;
808 } 831 }
809 832
810 internal static IEnumerable<T> IteratorToIEnumerable<T>(IntPtr iterator) 833 internal static IEnumerable<T> IteratorToIEnumerable<T>(IntPtr iterator)
diff --git a/src/lib/efl_mono/efl_mono_accessors.c b/src/lib/efl_mono/efl_mono_accessors.c
new file mode 100644
index 0000000..6482045
--- /dev/null
+++ b/src/lib/efl_mono/efl_mono_accessors.c
@@ -0,0 +1,93 @@
1/*
2 * Copyright 2019 by its authors. See AUTHORS.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17
18
19#include "Eina.h"
20
21#ifdef EAPI
22# undef EAPI
23#endif
24
25#ifdef _WIN32
26# define EAPI __declspec(dllexport)
27#else
28# ifdef __GNUC__
29# if __GNUC__ >= 4
30# define EAPI __attribute__ ((visibility("default")))
31# else
32# define EAPI
33# endif
34# else
35# define EAPI
36# endif
37#endif /* ! _WIN32 */
38
39// This just a wrapper around carray acessors for pinned managed data
40// It uses the free callback to unpin the managed data so it can be
41// reclaimed by the GC back in C# world.
42struct _Eina_Mono_Owned_Accessor
43{
44 Eina_Accessor accessor;
45
46 Eina_Accessor *carray_acc;
47 void *free_data;
48 Eina_Free_Cb free_cb;
49};
50
51typedef struct _Eina_Mono_Owned_Accessor Eina_Mono_Owned_Accessor;
52
53static Eina_Bool eina_mono_owned_carray_get_at(Eina_Mono_Owned_Accessor *accessor, unsigned int idx, void **data)
54{
55 return eina_accessor_data_get(accessor->carray_acc, idx, data);
56}
57
58static void** eina_mono_owned_carray_get_container(Eina_Mono_Owned_Accessor *accessor)
59{
60 // Is another accessor a valid container?
61 return (void**)&accessor->carray_acc;
62}
63
64static void eina_mono_owned_carray_free_cb(Eina_Mono_Owned_Accessor* accessor)
65{
66 accessor->free_cb(accessor->free_data);
67
68 free(accessor->carray_acc); // From Eina_CArray_Length_Accessor implementation...
69
70 free(accessor);
71}
72
73EAPI Eina_Accessor *eina_mono_owned_carray_length_accessor_new(void** array, unsigned int step, unsigned int length, Eina_Free_Cb free_cb, void *handle)
74{
75 Eina_Mono_Owned_Accessor *accessor = calloc(1, sizeof(Eina_Mono_Owned_Accessor));
76 if (!accessor) return NULL;
77
78 EINA_MAGIC_SET(&accessor->accessor, EINA_MAGIC_ACCESSOR);
79
80 accessor->carray_acc = eina_carray_length_accessor_new(array, step, length);
81
82 accessor->accessor.version = EINA_ACCESSOR_VERSION;
83 accessor->accessor.get_at = FUNC_ACCESSOR_GET_AT(eina_mono_owned_carray_get_at);
84 accessor->accessor.get_container = FUNC_ACCESSOR_GET_CONTAINER(eina_mono_owned_carray_get_container);
85 accessor->accessor.free = FUNC_ACCESSOR_FREE(eina_mono_owned_carray_free_cb);
86
87 // The managed callback to be called with the pinned data.
88 accessor->free_cb = free_cb;
89 // The managed pinned data to be unpinned.
90 accessor->free_data = handle;
91
92 return &accessor->accessor;
93} \ No newline at end of file
diff --git a/src/tests/efl_mono/Eo.cs b/src/tests/efl_mono/Eo.cs
index 586a18c..6f50d8f 100644
--- a/src/tests/efl_mono/Eo.cs
+++ b/src/tests/efl_mono/Eo.cs
@@ -257,18 +257,21 @@ class TestVariables
257 257
258class TestEoAccessors 258class TestEoAccessors
259{ 259{
260 private static void do_eo_accessors(IEnumerable<int> accessor) 260 private static void do_eo_accessors(IEnumerable<int> accessor, bool shouldMove=false)
261 { 261 {
262 var obj = new Dummy.TestObject(); 262 var obj = new Dummy.TestObject();
263 263
264 IEnumerable<int> acc = obj.CloneAccessor(accessor); 264 IEnumerable<int> source = shouldMove ? accessor.ToList() : accessor;
265 265
266 var zipped = acc.Zip(accessor, (first, second) => new Tuple<int, int>(first, second)); 266 IEnumerable<int> acc = shouldMove ? obj.CloneAccessorOwn(accessor) : obj.CloneAccessor(accessor);
267
268 var zipped = acc.Zip(source, (first, second) => new Tuple<int, int>(first, second));
267 269
268 foreach (Tuple<int, int> pair in zipped) 270 foreach (Tuple<int, int> pair in zipped)
269 { 271 {
270 Test.AssertEquals(pair.Item1, pair.Item2); 272 Test.AssertEquals(pair.Item1, pair.Item2);
271 } 273 }
274
272 obj.Dispose(); 275 obj.Dispose();
273 } 276 }
274 277
@@ -280,16 +283,26 @@ class TestEoAccessors
280 lst.Append(2); 283 lst.Append(2);
281 lst.Append(5); 284 lst.Append(5);
282 285
283 // FIXME: Replace the first accessor with the list once Eina.List implements Eina.IList
284 do_eo_accessors(lst.GetAccessor()); 286 do_eo_accessors(lst.GetAccessor());
285 287
286 lst.Dispose(); 288 lst.Dispose();
287 } 289 }
290 public static void eina_eo_accessors_own()
291 {
292 Eina.List<int> lst = new Eina.List<int>();
293 lst.Append(4);
294 lst.Append(3);
295 lst.Append(2);
296 lst.Append(1);
297 Eina.Accessor<int> acc = lst.GetAccessor();
298 do_eo_accessors(acc, shouldMove : true);
299
300 Test.Assert(!acc.Own);
301
302 }
288 303
289 public static void managed_eo_accessors() 304 public static void managed_eo_accessors()
290 { 305 {
291 var obj = new Dummy.TestObject();
292
293 List<int> lst = new List<int>(); 306 List<int> lst = new List<int>();
294 lst.Add(-1); 307 lst.Add(-1);
295 lst.Add(1); 308 lst.Add(1);
@@ -298,6 +311,17 @@ class TestEoAccessors
298 311
299 do_eo_accessors(lst); 312 do_eo_accessors(lst);
300 } 313 }
314
315 public static void managed_eo_accessors_own()
316 {
317 List<int> lst = new List<int>();
318 lst.Add(-1);
319 lst.Add(1);
320 lst.Add(4);
321 lst.Add(42);
322
323 do_eo_accessors(lst, shouldMove : true);
324 }
301} 325}
302 326
303class TestEoFinalize 327class TestEoFinalize
diff --git a/src/tests/efl_mono/dummy_test_object.c b/src/tests/efl_mono/dummy_test_object.c
index fb87a8c..d9ab519 100644
--- a/src/tests/efl_mono/dummy_test_object.c
+++ b/src/tests/efl_mono/dummy_test_object.c
@@ -4683,6 +4683,23 @@ Eina_Accessor *_dummy_test_object_clone_accessor(Eo *obj EINA_UNUSED, Dummy_Test
4683 return eina_list_accessor_new(pd->list_for_accessor); 4683 return eina_list_accessor_new(pd->list_for_accessor);
4684} 4684}
4685 4685
4686Eina_Accessor *_dummy_test_object_clone_accessor_own(Eo *obj EINA_UNUSED, Dummy_Test_Object_Data *pd, Eina_Accessor *acc)
4687{
4688 if (pd->list_for_accessor)
4689 eina_list_free(pd->list_for_accessor);
4690
4691 unsigned int i;
4692 int *data;
4693 EINA_ACCESSOR_FOREACH(acc, i, data)
4694 {
4695 pd->list_for_accessor = eina_list_append(pd->list_for_accessor, data);
4696 }
4697
4698 eina_accessor_free(acc);
4699
4700 return eina_list_accessor_new(pd->list_for_accessor);
4701}
4702
4686void _dummy_test_object_dummy_test_iface_emit_nonconflicted(Eo *obj, Dummy_Test_Object_Data *pd EINA_UNUSED) 4703void _dummy_test_object_dummy_test_iface_emit_nonconflicted(Eo *obj, Dummy_Test_Object_Data *pd EINA_UNUSED)
4687{ 4704{
4688 efl_event_callback_legacy_call(obj, DUMMY_TEST_IFACE_EVENT_NONCONFLICTED, NULL); 4705 efl_event_callback_legacy_call(obj, DUMMY_TEST_IFACE_EVENT_NONCONFLICTED, NULL);
diff --git a/src/tests/efl_mono/dummy_test_object.eo b/src/tests/efl_mono/dummy_test_object.eo
index 1852160..cf2ae7c 100644
--- a/src/tests/efl_mono/dummy_test_object.eo
+++ b/src/tests/efl_mono/dummy_test_object.eo
@@ -1621,6 +1621,13 @@ class Dummy.Test_Object extends Efl.Object implements Dummy.Test_Iface {
1621 return: accessor<int> @move; 1621 return: accessor<int> @move;
1622 } 1622 }
1623 1623
1624 clone_accessor_own {
1625 params {
1626 @in acc: accessor<int> @move;
1627 }
1628 return: accessor<int> @move;
1629 }
1630
1624 @property setter_only { 1631 @property setter_only {
1625 set {} 1632 set {}
1626 values { 1633 values {