Fixed deadlock in BMv2 device context service
Also minor refactoring of synchronized blocks.
Change-Id: Ifea25208ca4f1839bb3f21ba5b5ecfb2441baa35
diff --git a/protocols/bmv2/ctl/src/main/java/org/onosproject/bmv2/ctl/Bmv2DeviceContextServiceImpl.java b/protocols/bmv2/ctl/src/main/java/org/onosproject/bmv2/ctl/Bmv2DeviceContextServiceImpl.java
index 4727913..c6f3d04 100644
--- a/protocols/bmv2/ctl/src/main/java/org/onosproject/bmv2/ctl/Bmv2DeviceContextServiceImpl.java
+++ b/protocols/bmv2/ctl/src/main/java/org/onosproject/bmv2/ctl/Bmv2DeviceContextServiceImpl.java
@@ -60,6 +60,8 @@
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.onosproject.bmv2.api.context.Bmv2DefaultConfiguration.parse;
@@ -87,7 +89,7 @@
private final ScheduledExecutorService scheduledExecutor = SharedScheduledExecutors.getPoolThreadExecutor();
private final MapEventListener<DeviceId, Bmv2DeviceContext> contextListener = new ContextMapEventListener();
- private final ConcurrentMap<DeviceId, Boolean> deviceLocks = Maps.newConcurrentMap();
+ private final ConcurrentMap<DeviceId, Lock> deviceLocks = Maps.newConcurrentMap();
private ConsistentMap<DeviceId, Bmv2DeviceContext> contexts;
private Map<String, ClassLoader> interpreterClassLoaders;
@@ -115,7 +117,7 @@
interpreterClassLoaders = Maps.newConcurrentMap();
registerInterpreterClassLoader(defaultInterpreter.getClass(), this.getClass().getClassLoader());
- contexts.addListener(contextListener);
+ contexts.addListener(contextListener, scheduledExecutor);
if (configChecker != null && configChecker.isCancelled()) {
configChecker.cancel(false);
@@ -169,16 +171,14 @@
return defaultContext;
}
- private void configCheck(DeviceId deviceId) {
+ private void configCheck(DeviceId deviceId, Bmv2DeviceContext storedContext) {
+ if (storedContext == null) {
+ return;
+ }
// Synchronize executions over the same deviceId.
- deviceLocks.putIfAbsent(deviceId, new Boolean(true));
- synchronized (deviceLocks.get(deviceId)) {
-
- Bmv2DeviceContext storedContext = getContext(deviceId);
- if (storedContext == null) {
- return;
- }
-
+ Lock lock = deviceLocks.computeIfAbsent(deviceId, did -> new ReentrantLock());
+ lock.lock();
+ try {
log.trace("Executing configuration check on {}...", deviceId);
try {
@@ -200,18 +200,20 @@
} catch (Bmv2RuntimeException e) {
log.warn("Unable to dump JSON configuration from {}: {}", deviceId, e.explain());
}
+ } finally {
+ lock.unlock();
}
}
- private void triggerConfigCheck(DeviceId deviceId) {
+ private void triggerConfigCheck(DeviceId deviceId, Bmv2DeviceContext context) {
if (mastershipService.isLocalMaster(deviceId)) {
- scheduledExecutor.schedule(() -> configCheck(deviceId), 0, TimeUnit.SECONDS);
+ scheduledExecutor.schedule(() -> configCheck(deviceId, context), 0, TimeUnit.SECONDS);
}
}
private void checkDevices() {
deviceService.getAvailableDevices().forEach(device -> {
- triggerConfigCheck(device.id());
+ triggerConfigCheck(device.id(), getContext(device.id()));
});
}
@@ -234,7 +236,7 @@
DeviceId deviceId = event.key();
if (event.type().equals(INSERT) || event.type().equals(UPDATE)) {
log.trace("Context {} for {}", event.type().name(), deviceId);
- triggerConfigCheck(deviceId);
+ triggerConfigCheck(deviceId, event.newValue().value());
}
}
}