Add additinal sync
- Change how some internals in AbstractStateMachine are synchronized to limit changes for deadlock. - Relates #359
This commit is contained in:
@@ -116,6 +116,7 @@ public abstract class AbstractStateMachine<S, E> extends StateMachineObjectSuppo
|
||||
private volatile Message<E> forwardedInitialEvent;
|
||||
|
||||
private final Object lock = new Object();
|
||||
private final Object lock2 = new Object();
|
||||
|
||||
private StateMachine<S, E> parentMachine;
|
||||
|
||||
@@ -211,30 +212,9 @@ public abstract class AbstractStateMachine<S, E> extends StateMachineObjectSuppo
|
||||
|
||||
@Override
|
||||
public boolean sendEvent(Message<E> event) {
|
||||
if (hasStateMachineError()) {
|
||||
// TODO: should we throw exception?
|
||||
notifyEventNotAccepted(buildStateContext(Stage.EVENT_NOT_ACCEPTED, event, null, getRelayStateMachine(), getState(), null));
|
||||
return false;
|
||||
synchronized (lock2) {
|
||||
return sendEventInternal(event);
|
||||
}
|
||||
|
||||
try {
|
||||
event = getStateMachineInterceptors().preEvent(event, this);
|
||||
} catch (Exception e) {
|
||||
log.info("Event " + event + " threw exception in interceptors, not accepting event");
|
||||
notifyEventNotAccepted(buildStateContext(Stage.EVENT_NOT_ACCEPTED, event, null, getRelayStateMachine(), getState(), null));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isComplete() || !isRunning()) {
|
||||
notifyEventNotAccepted(buildStateContext(Stage.EVENT_NOT_ACCEPTED, event, null, getRelayStateMachine(), getState(), null));
|
||||
return false;
|
||||
}
|
||||
boolean accepted = acceptEvent(event);
|
||||
stateMachineExecutor.execute();
|
||||
if (!accepted) {
|
||||
notifyEventNotAccepted(buildStateContext(Stage.EVENT_NOT_ACCEPTED, event, null, getRelayStateMachine(), getState(), null));
|
||||
}
|
||||
return accepted;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -555,6 +535,33 @@ public abstract class AbstractStateMachine<S, E> extends StateMachineObjectSuppo
|
||||
forwardedInitialEvent = message;
|
||||
}
|
||||
|
||||
private boolean sendEventInternal(Message<E> event) {
|
||||
if (hasStateMachineError()) {
|
||||
// TODO: should we throw exception?
|
||||
notifyEventNotAccepted(buildStateContext(Stage.EVENT_NOT_ACCEPTED, event, null, getRelayStateMachine(), getState(), null));
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
event = getStateMachineInterceptors().preEvent(event, this);
|
||||
} catch (Exception e) {
|
||||
log.info("Event " + event + " threw exception in interceptors, not accepting event");
|
||||
notifyEventNotAccepted(buildStateContext(Stage.EVENT_NOT_ACCEPTED, event, null, getRelayStateMachine(), getState(), null));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isComplete() || !isRunning()) {
|
||||
notifyEventNotAccepted(buildStateContext(Stage.EVENT_NOT_ACCEPTED, event, null, getRelayStateMachine(), getState(), null));
|
||||
return false;
|
||||
}
|
||||
boolean accepted = acceptEvent(event);
|
||||
stateMachineExecutor.execute();
|
||||
if (!accepted) {
|
||||
notifyEventNotAccepted(buildStateContext(Stage.EVENT_NOT_ACCEPTED, event, null, getRelayStateMachine(), getState(), null));
|
||||
}
|
||||
return accepted;
|
||||
}
|
||||
|
||||
private StateMachine<S, E> getRelayStateMachine() {
|
||||
return relay != null ? relay : this;
|
||||
}
|
||||
@@ -924,11 +931,18 @@ public abstract class AbstractStateMachine<S, E> extends StateMachineObjectSuppo
|
||||
return null;
|
||||
}
|
||||
|
||||
synchronized void setCurrentState(State<S, E> state, Message<E> message, Transition<S, E> transition, boolean exit, StateMachine<S, E> stateMachine) {
|
||||
void setCurrentState(State<S, E> state, Message<E> message, Transition<S, E> transition, boolean exit, StateMachine<S, E> stateMachine) {
|
||||
setCurrentState(state, message, transition, exit, stateMachine, null, null);
|
||||
}
|
||||
|
||||
synchronized void setCurrentState(State<S, E> state, Message<E> message, Transition<S, E> transition, boolean exit,
|
||||
void setCurrentState(State<S, E> state, Message<E> message, Transition<S, E> transition, boolean exit,
|
||||
StateMachine<S, E> stateMachine, Collection<State<S, E>> sources, Collection<State<S, E>> targets) {
|
||||
synchronized (lock2) {
|
||||
setCurrentStateInternal(state, message, transition, exit, stateMachine, sources, targets);
|
||||
}
|
||||
}
|
||||
|
||||
private void setCurrentStateInternal(State<S, E> state, Message<E> message, Transition<S, E> transition, boolean exit,
|
||||
StateMachine<S, E> stateMachine, Collection<State<S, E>> sources, Collection<State<S, E>> targets) {
|
||||
State<S, E> findDeep = findDeepParent(state);
|
||||
boolean isTargetSubOf = false;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
* Copyright 2016-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -59,6 +59,11 @@ public class ActionAndTimerTests extends AbstractStateMachineTests {
|
||||
assertThat(testTimerAction.latch.await(4, TimeUnit.SECONDS), is(true));
|
||||
assertThat(testTimerAction.e, nullValue());
|
||||
|
||||
// need to sleep for TimerTrigger not causing
|
||||
// next event to get handled with threads, thus
|
||||
// causing interrupt
|
||||
Thread.sleep(1000);
|
||||
|
||||
machine.sendEvent(TestEvents.E2);
|
||||
assertThat(testListener.s3EnteredLatch.await(2, TimeUnit.SECONDS), is(true));
|
||||
assertThat(machine.getState().getIds(), containsInAnyOrder(TestStates.S3));
|
||||
@@ -84,6 +89,11 @@ public class ActionAndTimerTests extends AbstractStateMachineTests {
|
||||
assertThat(testTimerAction.latch.await(4, TimeUnit.SECONDS), is(true));
|
||||
assertThat(testTimerAction.e, nullValue());
|
||||
|
||||
// need to sleep for TimerTrigger not causing
|
||||
// next event to get handled with threads, thus
|
||||
// causing interrupt
|
||||
Thread.sleep(1000);
|
||||
|
||||
machine.sendEvent(TestEvents.E2);
|
||||
assertThat(testListener.s3EnteredLatch.await(2, TimeUnit.SECONDS), is(true));
|
||||
assertThat(machine.getState().getIds(), containsInAnyOrder(TestStates.S3));
|
||||
|
||||
Reference in New Issue
Block a user