2019-10-24 06:01:50 -07:00
|
|
|
/*
|
|
|
|
* Copyright 2019 by its authors. See AUTHORS.
|
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
2019-01-14 16:07:49 -08:00
|
|
|
using System;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.Linq;
|
|
|
|
using System.Runtime.InteropServices;
|
|
|
|
using System.Runtime.CompilerServices;
|
|
|
|
|
|
|
|
using EinaTestData;
|
|
|
|
using static EinaTestData.BaseData;
|
|
|
|
|
|
|
|
namespace TestSuite
|
|
|
|
{
|
|
|
|
|
|
|
|
class TestInheritance
|
|
|
|
{
|
|
|
|
internal class Inherit1 : Dummy.TestObject
|
|
|
|
{
|
|
|
|
override public void IntOut (int x, out int y)
|
|
|
|
{
|
|
|
|
y = 10*x;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-21 10:38:45 -07:00
|
|
|
internal class Inherit2 : Dummy.TestObject, Dummy.IInheritIface
|
2019-01-14 16:07:49 -08:00
|
|
|
{
|
|
|
|
override public void IntOut (int x, out int y)
|
|
|
|
{
|
2019-01-17 04:33:09 -08:00
|
|
|
Console.WriteLine("IntOut");
|
2019-01-14 16:07:49 -08:00
|
|
|
y = 10*x;
|
|
|
|
}
|
|
|
|
|
|
|
|
public string StringshareTest (string i)
|
|
|
|
{
|
2019-01-17 04:33:09 -08:00
|
|
|
Console.WriteLine("StringshareTest");
|
2019-01-14 16:07:49 -08:00
|
|
|
return "Hello World";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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: https://phab.enlightenment.org/D9014
2019-05-31 13:43:11 -07:00
|
|
|
internal class Inherit3Parent : Dummy.TestObject
|
|
|
|
{
|
|
|
|
public bool disposed = false;
|
|
|
|
public bool childDisposed = false;
|
|
|
|
|
|
|
|
~Inherit3Parent()
|
|
|
|
{
|
|
|
|
Console.WriteLine("finalizer called for parent");
|
|
|
|
}
|
|
|
|
|
|
|
|
protected override void Dispose(bool disposing)
|
|
|
|
{
|
|
|
|
Console.WriteLine("Dispose parent");
|
|
|
|
base.Dispose(disposing);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal class Inherit3Child : Dummy.TestObject
|
|
|
|
{
|
2019-07-08 08:53:41 -07:00
|
|
|
//Inherit3Parent parent;
|
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: https://phab.enlightenment.org/D9014
2019-05-31 13:43:11 -07:00
|
|
|
public Inherit3Child(Inherit3Parent parent) : base(parent)
|
|
|
|
{
|
|
|
|
// WARNING: Uncommenting the line below causes the parent-child cycle to leak.
|
|
|
|
// The GC won't be able to collect it.
|
|
|
|
// this.parent = parent;
|
|
|
|
}
|
|
|
|
|
|
|
|
~Inherit3Child()
|
|
|
|
{
|
|
|
|
Console.WriteLine("finalizer called for child");
|
|
|
|
}
|
|
|
|
|
|
|
|
protected override void Dispose(bool disposing)
|
|
|
|
{
|
|
|
|
/* parent.childDisposed = true; */
|
|
|
|
Console.WriteLine("Dispose parent");
|
|
|
|
base.Dispose(disposing);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-14 16:07:49 -08:00
|
|
|
public static void test_inherit_from_regular_class()
|
|
|
|
{
|
|
|
|
var obj = new Inherit1();
|
|
|
|
int i = Dummy.InheritHelper.ReceiveDummyAndCallIntOut(obj);
|
|
|
|
Test.AssertEquals (50, i);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void test_inherit_from_iface()
|
|
|
|
{
|
|
|
|
var obj = new Inherit2();
|
|
|
|
int i = Dummy.InheritHelper.ReceiveDummyAndCallIntOut(obj);
|
|
|
|
Test.AssertEquals (50, i);
|
2019-01-17 04:33:09 -08:00
|
|
|
string s = Dummy.InheritHelper.ReceiveDummyAndCallInStringshare(obj);
|
2019-01-14 16:07:49 -08:00
|
|
|
Test.AssertEquals ("Hello World", s);
|
|
|
|
}
|
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: https://phab.enlightenment.org/D9014
2019-05-31 13:43:11 -07:00
|
|
|
|
|
|
|
private static void CreateAndCheckInheritedObjects(out WeakReference parentWRef, out WeakReference childWRef)
|
|
|
|
{
|
|
|
|
var parent = new Inherit3Parent();
|
|
|
|
var child = new Inherit3Child(parent);
|
|
|
|
|
|
|
|
parentWRef = new WeakReference(parent);
|
|
|
|
childWRef = new WeakReference(child);
|
|
|
|
|
|
|
|
child = null;
|
|
|
|
|
|
|
|
System.GC.Collect(System.GC.MaxGeneration, GCCollectionMode.Forced, true, true);
|
|
|
|
System.GC.WaitForPendingFinalizers();
|
|
|
|
Efl.App.AppMain.Iterate();
|
|
|
|
|
|
|
|
child = (Inherit3Child) childWRef.Target;
|
|
|
|
|
|
|
|
Test.AssertNotNull(parent);
|
|
|
|
Test.AssertNotNull(child);
|
|
|
|
Test.AssertEquals(false, parent.disposed);
|
|
|
|
Test.AssertEquals(false, parent.childDisposed);
|
|
|
|
|
|
|
|
parent = null;
|
|
|
|
child = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void test_inherit_lifetime()
|
|
|
|
{
|
|
|
|
WeakReference parentWRef;
|
|
|
|
WeakReference childWRef;
|
|
|
|
|
|
|
|
CreateAndCheckInheritedObjects(out parentWRef, out childWRef);
|
|
|
|
|
|
|
|
// Two invocations to iterate a the child wasn't being released with a single one
|
|
|
|
Test.CollectAndIterate();
|
|
|
|
Test.CollectAndIterate();
|
|
|
|
|
|
|
|
var parent = (Dummy.TestObject) parentWRef.Target;
|
|
|
|
var child = (Dummy.TestObject) childWRef.Target;
|
|
|
|
|
|
|
|
Test.AssertNull(parent);
|
|
|
|
Test.AssertNull(child);
|
|
|
|
}
|
2019-01-14 16:07:49 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|