Deadlock during EPackage initialization for cyclic package interdependencies [message #1695038] |
Mon, 11 May 2015 14:17 |
Idrissa Dieng Messages: 11 Registered: April 2013 Location: Paris, France |
Junior Member |
|
|
Hi all,
We encountered a deadlock problem during EMF packages initialization when using at least 2 threads. Indeed, there are cyclic package interdependencies between the various packages of our metamodel and we observed the issue when thread-1 triggers a package initialization and the thread-2 tries getting the eINSTANCE field via Java reflexivity (EPackage.Descriptor#getEPackage()).
The following describes the stack trace:
• Worker-1 starts at first & Worker-2 stats after Worker-1
• Worker-2 tries initiating EcucparameterdefPackageImpl.init() (that tries acceding to EcuresourcePackageImpl (see line in stack trace))
• Worked-1 tries acceding to EcucdescriptionPackageImpl.init() (after Worker-2 has started and that tries acceding EcucparameterdefPackageImpl)
==== Worker-1 (starts at first)
sun.misc.Unsafe.ensureClassInitialized(Class)
sun.reflect.UnsafeFieldAccessorFactory.newFieldAccessor(Field, boolean)
sun.reflect.ReflectionFactory.newFieldAccessor(Field, boolean)
java.lang.reflect.Field.acquireFieldAccessor(boolean)
java.lang.reflect.Field.getFieldAccessor(Object)
java.lang.reflect.Field.get(Object)
org.eclipse.emf.ecore.plugin.RegistryReader$EPackageDescriptor.getEPackage()
RegistryReader.java:273
org.eclipse.emf.ecore.impl.EPackageImpl$1.getEPackage()
EPackageImpl.java:163
org.eclipse.emf.ecore.impl.EPackageRegistryImpl.getEPackage(String)
EPackageRegistryImpl.java:127
autosar40.ecucdescription.impl.EcucdescriptionPackageImpl.init()
EcucdescriptionPackageImpl.java:1202
autosar40.ecucdescription.EcucdescriptionPackage.<clinit>()
...
autosar40.ecuresource.impl.EcuresourcePackageImpl.init()
EcuresourcePackageImpl.java:1051
autosar40.ecuresource.EcuresourcePackage.<clinit>()
EcuresourcePackage.java:78
sun.misc.Unsafe.ensureClassInitialized(Class)
sun.reflect.UnsafeFieldAccessorFactory.newFieldAccessor(Field, boolean)
sun.reflect.ReflectionFactory.newFieldAccessor(Field, boolean)
java.lang.reflect.Field.acquireFieldAccessor(boolean)
java.lang.reflect.Field.getFieldAccessor(Object)
java.lang.reflect.Field.get(Object)
org.eclipse.emf.ecore.plugin.RegistryReader$EPackageDescriptor.getEPackage()
RegistryReader.java:273
org.eclipse.emf.ecore.impl.EPackageRegistryImpl.getEPackage(String)
EPackageRegistryImpl.java:127
autosar40.commonstructure.internalbehavior.impl.InternalbehaviorPackageImpl.init()
InternalbehaviorPackageImpl.java:1036
autosar40.commonstructure.internalbehavior.InternalbehaviorPackage.<clinit>()
InternalbehaviorPackage.java:79
xyz.sym10.impl.Sym10PackageImpl.init()
Sym10PackageImpl.java:2810
xyz.Sym10Package.<clinit>() Sym10Package.java:71
sun.misc.Unsafe.ensureClassInitialized(Class)
sun.reflect.UnsafeFieldAccessorFactory.newFieldAccessor(Field, boolean)
sun.reflect.ReflectionFactory.newFieldAccessor(Field, boolean)
java.lang.reflect.Field.acquireFieldAccessor(boolean)
java.lang.reflect.Field.getFieldAccessor(Object)
java.lang.reflect.Field.get(Object)
org.eclipse.emf.ecore.plugin.RegistryReader$EPackageDescriptor.getEPackage()
RegistryReader.java:273
org.eclipse.emf.ecore.impl.EPackageRegistryImpl.getEPackage(String)
...
==== Worker-2 (starts after Worker-1)
sun.misc.Unsafe.ensureClassInitialized(Class)
sun.reflect.UnsafeFieldAccessorFactory.newFieldAccessor(Field, boolean)
sun.reflect.ReflectionFactory.newFieldAccessor(Field, boolean)
java.lang.reflect.Field.acquireFieldAccessor(boolean)
java.lang.reflect.Field.getFieldAccessor(Object)
java.lang.reflect.Field.get(Object)
org.eclipse.emf.ecore.plugin.RegistryReader$EPackageDescriptor.getEPackage()
RegistryReader.java:273
org.eclipse.emf.ecore.impl.EPackageImpl$1.getEPackage()
EPackageImpl.java:163
org.eclipse.emf.ecore.impl.EPackageRegistryImpl.getEPackage(String)
autosar40.ecucparameterdef.impl.EcucparameterdefPackageImpl.init()
autosar40.ecucparameterdef.EcucparameterdefPackage.<clinit>()
org.artop.ecuc.autosar4x.dsl.values.ecucValuesDsl.impl.EcucValuesDslPackageImpl.init()
org.artop.ecuc.autosar4x.dsl.values.ecucValuesDsl.EcucValuesDslPackage.<clinit>()
xyz.ecuc.values.validation.internal.EcucValuesDslExternalValidatorDelegate.getEPackages()
...
Changed the EPackageImpl implementation as described below fixed the deadlock issue in our side. We know that the original EMF code is there for some reasons. Therefore, why not returning the same EPackage instances also when the threads are different?
Can you please tell us if using the same EPackage instances will have side effects? Or do you have any suggestion(s) for resolving this deadlock issue?
Original EMF Code
protected EPackageImpl(String packageURI, final EFactory factory)
{
super();
Object registration = Registry.INSTANCE.get(packageURI);
if (registration instanceof Descriptor)
{
final Descriptor descriptor = (Descriptor)registration;
final long threadId = Thread.currentThread().getId();
Registry.INSTANCE.put
(packageURI,
new Descriptor()
{
public EPackage getEPackage()
{
return Thread.currentThread().getId() == threadId ? EPackageImpl.this : descriptor.getEPackage();
}
public EFactory getEFactory()
{
return Thread.currentThread().getId() == threadId ? factory : descriptor.getEFactory();
}
});
}
...
}
Our solution to fix the deadlock issue is returning always EPackageImpl.this & factory to use same instances.
Thanks in advance
|
|
|
Re: Deadlock during EPackage initialization for cyclic package interdependencies [message #1695051 is a reply to message #1695038] |
Mon, 11 May 2015 15:35 |
Ed Merks Messages: 33141 Registered: July 2009 |
Senior Member |
|
|
Idrissa,
Comments below.
On 11/05/2015 4:17 PM, Idrissa Dieng wrote:
> Hi all,
> We encountered a deadlock problem during EMF packages initialization
> when using at least 2 threads.
Which version of EMF?
> Indeed, there are cyclic package interdependencies between the various
> packages of our metamodel and we observed the issue when thread-1
> triggers a package initialization and the thread-2 tries getting the
> eINSTANCE field via Java reflexivity (EPackage.Descriptor#getEPackage()).
> The following describes the stack trace:
> • Worker-1 starts at first & Worker-2 stats after Worker-1
> • Worker-2 tries initiating EcucparameterdefPackageImpl.init()
> (that tries acceding to EcuresourcePackageImpl (see line in stack trace))
> • Worked-1 tries acceding to EcucdescriptionPackageImpl.init()
> (after Worker-2 has started and that tries acceding
> EcucparameterdefPackageImpl)
>
> ==== Worker-1 (starts at first)
> sun.misc.Unsafe.ensureClassInitialized(Class)
> sun.reflect.UnsafeFieldAccessorFactory.newFieldAccessor(Field, boolean)
> sun.reflect.ReflectionFactory.newFieldAccessor(Field, boolean)
> java.lang.reflect.Field.acquireFieldAccessor(boolean)
> java.lang.reflect.Field.getFieldAccessor(Object)
> java.lang.reflect.Field.get(Object)
> org.eclipse.emf.ecore.plugin.RegistryReader$EPackageDescriptor.getEPackage()
>
> RegistryReader.java:273
> org.eclipse.emf.ecore.impl.EPackageImpl$1.getEPackage()
> EPackageImpl.java:163
> org.eclipse.emf.ecore.impl.EPackageRegistryImpl.getEPackage(String)
> EPackageRegistryImpl.java:127
> autosar40.ecucdescription.impl.EcucdescriptionPackageImpl.init()
> EcucdescriptionPackageImpl.java:1202
> autosar40.ecucdescription.EcucdescriptionPackage.<clinit>()
> ..
> autosar40.ecuresource.impl.EcuresourcePackageImpl.init()
> EcuresourcePackageImpl.java:1051
> autosar40.ecuresource.EcuresourcePackage.<clinit>()
> EcuresourcePackage.java:78
> sun.misc.Unsafe.ensureClassInitialized(Class)
> sun.reflect.UnsafeFieldAccessorFactory.newFieldAccessor(Field, boolean)
> sun.reflect.ReflectionFactory.newFieldAccessor(Field, boolean)
> java.lang.reflect.Field.acquireFieldAccessor(boolean)
> java.lang.reflect.Field.getFieldAccessor(Object)
> java.lang.reflect.Field.get(Object)
> org.eclipse.emf.ecore.plugin.RegistryReader$EPackageDescriptor.getEPackage()
>
> RegistryReader.java:273
> org.eclipse.emf.ecore.impl.EPackageRegistryImpl.getEPackage(String)
> EPackageRegistryImpl.java:127
> autosar40.commonstructure.internalbehavior.impl.InternalbehaviorPackageImpl.init()
>
> InternalbehaviorPackageImpl.java:1036
> autosar40.commonstructure.internalbehavior.InternalbehaviorPackage.<clinit>()
>
> InternalbehaviorPackage.java:79
> xyz.sym10.impl.Sym10PackageImpl.init()
> Sym10PackageImpl.java:2810
> xyz.Sym10Package.<clinit>() Sym10Package.java:71
> sun.misc.Unsafe.ensureClassInitialized(Class)
> sun.reflect.UnsafeFieldAccessorFactory.newFieldAccessor(Field, boolean)
> sun.reflect.ReflectionFactory.newFieldAccessor(Field, boolean)
> java.lang.reflect.Field.acquireFieldAccessor(boolean)
> java.lang.reflect.Field.getFieldAccessor(Object)
> java.lang.reflect.Field.get(Object)
> org.eclipse.emf.ecore.plugin.RegistryReader$EPackageDescriptor.getEPackage()
>
> RegistryReader.java:273
> org.eclipse.emf.ecore.impl.EPackageRegistryImpl.getEPackage(String)
> ..
>
> ==== Worker-2 (starts after Worker-1)
> sun.misc.Unsafe.ensureClassInitialized(Class)
> sun.reflect.UnsafeFieldAccessorFactory.newFieldAccessor(Field, boolean)
> sun.reflect.ReflectionFactory.newFieldAccessor(Field, boolean)
> java.lang.reflect.Field.acquireFieldAccessor(boolean)
> java.lang.reflect.Field.getFieldAccessor(Object)
> java.lang.reflect.Field.get(Object)
> org.eclipse.emf.ecore.plugin.RegistryReader$EPackageDescriptor.getEPackage()
>
> RegistryReader.java:273
> org.eclipse.emf.ecore.impl.EPackageImpl$1.getEPackage()
> EPackageImpl.java:163
> org.eclipse.emf.ecore.impl.EPackageRegistryImpl.getEPackage(String)
> autosar40.ecucparameterdef.impl.EcucparameterdefPackageImpl.init()
> autosar40.ecucparameterdef.EcucparameterdefPackage.<clinit>()
> org.artop.ecuc.autosar4x.dsl.values.ecucValuesDsl.impl.EcucValuesDslPackageImpl.init()
> org.artop.ecuc.autosar4x.dsl.values.ecucValuesDsl.EcucValuesDslPackage.<clinit>()
>
> xyz.ecuc.values.validation.internal.EcucValuesDslExternalValidatorDelegate.getEPackages()
>
> ..
>
> Changed the EPackageImpl implementation as described below fixed the
> deadlock issue in our side. We know that the original EMF code is
> there for some reasons.
https://bugs.eclipse.org/bugs/show_bug.cgi?id=270865
> Therefore, why not returning the same EPackage instances also when the
> threads are different?
I'm not sure I understand the question...
> Can you please tell us if using the same EPackage instances will have
> side effects?
Given I don't understand the question, it's hard to comment.
> Or do you have any suggestion(s) for resolving this deadlock issue?
In the worst case, make sure you initialize the packages on a single
thread earlier during initialization.
>
> Original EMF Code
>
> protected EPackageImpl(String packageURI, final EFactory factory)
> {
> super();
>
> Object registration = Registry.INSTANCE.get(packageURI);
> if (registration instanceof Descriptor)
> {
> final Descriptor descriptor = (Descriptor)registration;
> final long threadId = Thread.currentThread().getId();
> Registry.INSTANCE.put
> (packageURI, new Descriptor()
> {
> public EPackage getEPackage()
> {
> return Thread.currentThread().getId() == threadId ?
> EPackageImpl.this : descriptor.getEPackage();
> }
>
> public EFactory getEFactory()
> {
> return Thread.currentThread().getId() == threadId ?
> factory : descriptor.getEFactory();
> }
> });
> }
> ...
> }
>
> Our solution to fix the deadlock issue is returning always
> EPackageImpl.this & factory to use same instances.
Another approach might be to access the XyzPackage.eINSTANCE values
earlier in the application.
In the end this problem is nasty and even Java is designed so that it's
possible that XyzPackage.eINSTANCE return null in a multi-thread
scenario because it ensures that class loading never deadlocks, at the
cost of constants that in theory can't possibly be null, in theory,
being null nevertheless.
>
> Thanks in advance
>
Ed Merks
Professional Support: https://www.macromodeling.com/
|
|
|
|
|
Powered by
FUDForum. Page generated in 0.03260 seconds