Hi everyone,

we recently found a strange deadlock problem; first seemed to be related to switching from 5.5.0-beta-1 to 5.5.0, at least in the full application it was easy to reproduce with the latter but (in a few manual tests) not with the beta.

after trying to reduce it to a minimal test case… it can be triggered with either (and 5.4.x); maybe in the "real" code the calls
take long enough to avoid the data race or at least make it unlikely.


on to the questions:

* has anyone seen something like this before? closest bug i can find is: https://issues.apache.org/jira/browse/TAPESTRY-2561

* is this likely related to registry startup? kinda afraid of same situation during normal operations, though once most/all services
are realized everything should be fine

thanks for reading & any hints you can offer

Regards,
Oliver


it appears all of the following is required:

* a builder method for a simple class (not a service); with some kind of call to IOC (inject anything)

public static SomeClass build(@Inject @Symbol("some.symbol") String uri) {
    return new SomeClass();
  }


* this class is a dependency for a shared service:

public class SharedImpl implements Shared {

  public SharedImpl(SomeClass iDoNothing) {
  }


* two services marked as eager-load; both require the shared service

  public static void bind(ServiceBinder binder) {
    binder.bind(JobAdder.class, JobAdderImpl.class).eagerLoad();
    binder.bind(Other.class, OtherImpl.class).eagerLoad();
    binder.bind(Shared.class, SharedImpl.class);
  }


* JobAdder c-tor adds Runnable(s) to PeriodicExecutor

  public JobAdderImpl(List<RunnableJobData> parts, PeriodicExecutor exec) {
    LOG.info("Blocked here?");

    for (RunnableJobData p : parts) {
exec.addJob(new ImmediateStartIntervalSchedule(1000 * 60), p.name, p.run);
    }
  }


* the Runnable and OtherImpl (c-tor) call the shared service (instances are realized)

  @Contribute(JobAdder.class)
public static void contributeJobParts(OrderedConfiguration conf, Shared something) {

    conf.add("abc", new RunnableJobData("abc", () -> {
      LOG.info("starting job");
      something.doFoo();


  public class OtherImpl implements Other {

    public OtherImpl(Shared xx) {
      xx.doFoo();


* the jobs start immediately (no initial delay)

  public class ImmediateStartIntervalSchedule extends IntervalSchedule {

    public ImmediateStartIntervalSchedule(final long interval) {
      super(interval);
    }

    @Override
    public long firstExecution() {
      return System.currentTimeMillis();
    }



probably the easiest fix (for us) is to avoid the immediate execution of periodic jobs while "RegistryImpl.performRegistryStartup" is still running on the main thread; e.g. adding the jobs from a @Startup method seems to work ok

maybe PeriodicExecutorImpl::start should be called from @Startup instead of @PostInjection (assuming startup methods are called after the
registry is done, while @PostInjection is called earlier?)


in the trace below both threads "hold" a R-lock, one also has (upgraded to) W, the second blocks on W … that seems wrong

https://github.com/apache/tapestry-5/blob/master/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/ConcurrentBarrier.java#L54
maybe reentrancy; but i'm not sure about the "upgrade R to W" logic



here is the test source: https://easyupload.io/xzy6j1


Found one Java-level deadlock:
=============================
"main":
waiting to lock monitor 0x00007f7f38008b80 (object 0x000000071554f4a8, a org.apache.tapestry5.ioc.internal.services.JustInTimeObjectCreator),
  which is held by "Tapestry PeriodicExecutor"
"Tapestry PeriodicExecutor":
waiting for ownable synchronizer 0x0000000716130940, (a java.util.concurrent.locks.ReentrantReadWriteLock$NonfairSync),
  which is held by "main"


"main":
at org.apache.tapestry5.ioc.internal.services.JustInTimeObjectCreator.obtainObjectFromCreator(JustInTimeObjectCreator.java:62) - waiting to lock <0x000000071554f4a8> (a org.apache.tapestry5.ioc.internal.services.JustInTimeObjectCreator) at org.apache.tapestry5.ioc.internal.services.JustInTimeObjectCreator.createObject(JustInTimeObjectCreator.java:55)
        at $SymbolSource_c9319bed00c.delegate(Unknown Source)
        at $SymbolSource_c9319bed00c.valueForSymbol(Unknown Source)
at org.apache.tapestry5.ioc.internal.services.SymbolObjectProvider.provide(SymbolObjectProvider.java:50)
at org.apache.tapestry5.ioc.internal.ModuleImpl$1.invoke(ModuleImpl.java:198) at org.apache.tapestry5.ioc.internal.util.ConcurrentBarrier.withWrite(ConcurrentBarrier.java:139) at org.apache.tapestry5.ioc.internal.ModuleImpl$2.invoke(ModuleImpl.java:215) at org.apache.tapestry5.ioc.internal.util.ConcurrentBarrier.withRead(ConcurrentBarrier.java:83) at org.apache.tapestry5.ioc.internal.ModuleImpl.findOrCreate(ModuleImpl.java:221) at org.apache.tapestry5.ioc.internal.ModuleImpl.getService(ModuleImpl.java:112)
at org.apache.tapestry5.ioc.internal.AbstractReloadableObjectCreator.createObject(AbstractReloadableObjectCreator.java:118) - locked <0x00000007154d53f8> (a org.apache.tapestry5.ioc.internal.ReloadableServiceImplementationObjectCreator)
        at $Shared_c9319bed012.delegate(Unknown Source)
        at $Shared_c9319bed012.doFoo(Unknown Source)
        at $Shared_c9319bed00e.doFoo(Unknown Source)
        at de.eddyson.t5.deadlock.OtherImpl.<init>(OtherImpl.java:8)
…
at org.apache.tapestry5.ioc.internal.services.JustInTimeObjectCreator.obtainObjectFromCreator(JustInTimeObjectCreator.java:67) - locked <0x00000007156584b0> (a org.apache.tapestry5.ioc.internal.services.JustInTimeObjectCreator) at org.apache.tapestry5.ioc.internal.services.JustInTimeObjectCreator.createObject(JustInTimeObjectCreator.java:55) at org.apache.tapestry5.ioc.internal.services.JustInTimeObjectCreator.eagerLoadService(JustInTimeObjectCreator.java:88) at org.apache.tapestry5.ioc.internal.RegistryImpl.performRegistryStartup(RegistryImpl.java:357) at org.apache.tapestry5.ioc.internal.RegistryWrapper.performRegistryStartup(RegistryWrapper.java:89)



"Tapestry PeriodicExecutor":
        at jdk.internal.misc.Unsafe.park(java.base@11.0.8/Native Method)
- parking to wait for <0x0000000716130940> (a java.util.concurrent.locks.ReentrantReadWriteLock$NonfairSync) at java.util.concurrent.locks.LockSupport.park(java.base@11.0.8/LockSupport.java:194) at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(java.base@11.0.8/AbstractQueuedSynchronizer.java:885) at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(java.base@11.0.8/AbstractQueuedSynchronizer.java:917) at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(java.base@11.0.8/AbstractQueuedSynchronizer.java:1240) at java.util.concurrent.locks.ReentrantReadWriteLock$WriteLock.lock(java.base@11.0.8/ReentrantReadWriteLock.java:959) at org.apache.tapestry5.ioc.internal.util.ConcurrentBarrier.withWrite(ConcurrentBarrier.java:135) at org.apache.tapestry5.ioc.internal.ModuleImpl$2.invoke(ModuleImpl.java:215) at org.apache.tapestry5.ioc.internal.util.ConcurrentBarrier.withRead(ConcurrentBarrier.java:83) at org.apache.tapestry5.ioc.internal.ModuleImpl.findOrCreate(ModuleImpl.java:221) at org.apache.tapestry5.ioc.internal.ModuleImpl.getService(ModuleImpl.java:112) at org.apache.tapestry5.ioc.internal.RegistryImpl.getService(RegistryImpl.java:497)
- locked <0x000000071554f4a8> (a org.apache.tapestry5.ioc.internal.services.JustInTimeObjectCreator) at org.apache.tapestry5.ioc.internal.services.JustInTimeObjectCreator.createObject(JustInTimeObjectCreator.java:55)
        at $SymbolSource_c9319bed00c.delegate(Unknown Source)
        at $SymbolSource_c9319bed00c.valueForSymbol(Unknown Source)
at org.apache.tapestry5.ioc.internal.services.SymbolObjectProvider.provide(SymbolObjectProvider.java:50)
at org.apache.tapestry5.ioc.internal.services.JustInTimeObjectCreator.obtainObjectFromCreator(JustInTimeObjectCreator.java:67) - locked <0x000000071548fd68> (a org.apache.tapestry5.ioc.internal.services.JustInTimeObjectCreator) at org.apache.tapestry5.ioc.internal.services.JustInTimeObjectCreator.createObject(JustInTimeObjectCreator.java:55)
        at $ParallelExecutor_c9319bed010.delegate(Unknown Source)
        at $ParallelExecutor_c9319bed010.invoke(Unknown Source)
at org.apache.tapestry5.ioc.internal.services.cron.PeriodicExecutorImpl$Job.start(PeriodicExecutorImpl.java:181) at org.apache.tapestry5.ioc.internal.services.cron.PeriodicExecutorImpl.executeCurrentBatch(PeriodicExecutorImpl.java:382) at org.apache.tapestry5.ioc.internal.services.cron.PeriodicExecutorImpl.run(PeriodicExecutorImpl.java:315)

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tapestry.apache.org
For additional commands, e-mail: users-h...@tapestry.apache.org

Reply via email to