src/share/classes/sun/rmi/server/Activation.java
Print this page
rev 3756 : 6896297: (rmi) fix ConcurrentModificationException causing TCK failure
Reviewed-by: XXX
*** 28,37 ****
--- 28,38 ----
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
+ import java.io.ObjectInputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.Serializable;
import java.lang.Process;
*** 96,105 ****
--- 97,107 ----
import java.util.Map;
import java.util.MissingResourceException;
import java.util.Properties;
import java.util.ResourceBundle;
import java.util.Set;
+ import java.util.concurrent.ConcurrentHashMap;
import sun.rmi.log.LogHandler;
import sun.rmi.log.ReliableLog;
import sun.rmi.registry.RegistryImpl;
import sun.rmi.runtime.NewThreadAction;
import sun.rmi.server.UnicastServerRef;
*** 145,158 ****
private static Method execPolicyMethod;
private static boolean debugExec;
/** maps activation id to its respective group id */
private Map<ActivationID,ActivationGroupID> idTable =
! new HashMap<ActivationID,ActivationGroupID>();
/** maps group id to its GroupEntry groups */
private Map<ActivationGroupID,GroupEntry> groupTable =
! new HashMap<ActivationGroupID,GroupEntry>();
private byte majorVersion = MAJOR_VERSION;
private byte minorVersion = MINOR_VERSION;
/** number of simultaneous group exec's */
--- 147,160 ----
private static Method execPolicyMethod;
private static boolean debugExec;
/** maps activation id to its respective group id */
private Map<ActivationID,ActivationGroupID> idTable =
! new ConcurrentHashMap<>();
/** maps group id to its GroupEntry groups */
private Map<ActivationGroupID,GroupEntry> groupTable =
! new ConcurrentHashMap<>();
private byte majorVersion = MAJOR_VERSION;
private byte minorVersion = MINOR_VERSION;
/** number of simultaneous group exec's */
*** 235,246 ****
shutdownHook = new ShutdownHook();
groupSemaphore = getInt("sun.rmi.activation.groupThrottle", 3);
groupCounter = 0;
Runtime.getRuntime().addShutdownHook(shutdownHook);
ActivationGroupID[] gids =
! groupTable.keySet().toArray(
! new ActivationGroupID[groupTable.size()]);
synchronized (startupLock = new Object()) {
// all the remote methods briefly synchronize on startupLock
// (via checkShutdown) to make sure they don't happen in the
// middle of this block. This block must not cause any such
--- 237,247 ----
shutdownHook = new ShutdownHook();
groupSemaphore = getInt("sun.rmi.activation.groupThrottle", 3);
groupCounter = 0;
Runtime.getRuntime().addShutdownHook(shutdownHook);
ActivationGroupID[] gids =
! groupTable.keySet().toArray(new ActivationGroupID[0]);
synchronized (startupLock = new Object()) {
// all the remote methods briefly synchronize on startupLock
// (via checkShutdown) to make sure they don't happen in the
// middle of this block. This block must not cause any such
*** 272,281 ****
--- 273,299 ----
e.printStackTrace();
}
}
}
+ /**
+ * Previous versions used HashMap instead of ConcurrentHashMap.
+ * Replace any HashMaps found during deserialization with
+ * ConcurrentHashMaps.
+ */
+ private void readObject(ObjectInputStream ois)
+ throws IOException, ClassNotFoundException
+ {
+ ois.defaultReadObject();
+ if (! (groupTable instanceof ConcurrentHashMap)) {
+ groupTable = new ConcurrentHashMap<>(groupTable);
+ }
+ if (! (idTable instanceof ConcurrentHashMap)) {
+ idTable = new ConcurrentHashMap<>(idTable);
+ }
+ }
+
private static class SystemRegistryImpl extends RegistryImpl {
private static final String NAME = ActivationSystem.class.getName();
private final ActivationSystem systemStub;
*** 486,498 ****
checkArgs(desc, null);
ActivationGroupID id = new ActivationGroupID(systemStub);
GroupEntry entry = new GroupEntry(id, desc);
// table insertion must take place before log update
- synchronized (groupTable) {
groupTable.put(id, entry);
- }
addLogRecord(new LogRegisterGroup(id, desc));
return id;
}
public ActivationMonitor activeGroup(ActivationGroupID id,
--- 504,514 ----
*** 513,527 ****
checkShutdown();
RegistryImpl.checkAccess("ActivationSystem.unregisterGroup");
// remove entry before unregister so state is updated before
// logged
! synchronized (groupTable) {
! GroupEntry entry = getGroupEntry(id);
! groupTable.remove(id);
! entry.unregisterGroup(true);
! }
}
public ActivationDesc setActivationDesc(ActivationID id,
ActivationDesc desc)
throws ActivationException, UnknownObjectException, RemoteException
--- 529,539 ----
checkShutdown();
RegistryImpl.checkAccess("ActivationSystem.unregisterGroup");
// remove entry before unregister so state is updated before
// logged
! removeGroupEntry(id).unregisterGroup(true);
}
public ActivationDesc setActivationDesc(ActivationID id,
ActivationDesc desc)
throws ActivationException, UnknownObjectException, RemoteException
*** 635,650 ****
*/
unexport(activator);
unexport(system);
// destroy all child processes (groups)
! GroupEntry[] groupEntries;
! synchronized (groupTable) {
! groupEntries = groupTable.values().
! toArray(new GroupEntry[groupTable.size()]);
! }
! for (GroupEntry groupEntry : groupEntries) {
groupEntry.shutdown();
}
Runtime.getRuntime().removeShutdownHook(shutdownHook);
--- 647,657 ----
*/
unexport(activator);
unexport(system);
// destroy all child processes (groups)
! for (GroupEntry groupEntry : groupTable.values()) {
groupEntry.shutdown();
}
Runtime.getRuntime().removeShutdownHook(shutdownHook);
*** 691,757 ****
synchronized (Activation.this) {
shuttingDown = true;
}
// destroy all child processes (groups) quickly
- synchronized (groupTable) {
for (GroupEntry groupEntry : groupTable.values()) {
groupEntry.shutdownFast();
}
}
}
- }
/**
* Returns the groupID for a given id of an object in the group.
* Throws UnknownObjectException if the object is not registered.
*/
private ActivationGroupID getGroupID(ActivationID id)
throws UnknownObjectException
{
- synchronized (idTable) {
ActivationGroupID groupID = idTable.get(id);
if (groupID != null) {
return groupID;
}
- }
throw new UnknownObjectException("unknown object: " + id);
}
/**
! * Returns the group entry for the group id. Throws
! * UnknownGroupException if the group is not registered.
*/
! private GroupEntry getGroupEntry(ActivationGroupID id)
throws UnknownGroupException
{
if (id.getClass() == ActivationGroupID.class) {
! synchronized (groupTable) {
! GroupEntry entry = groupTable.get(id);
if (entry != null && !entry.removed) {
return entry;
}
}
- }
throw new UnknownGroupException("group unknown");
}
/**
* Returns the group entry for the object's id. Throws
* UnknownObjectException if the object is not registered or the
* object's group is not registered.
*/
private GroupEntry getGroupEntry(ActivationID id)
throws UnknownObjectException
{
ActivationGroupID gid = getGroupID(id);
- synchronized (groupTable) {
GroupEntry entry = groupTable.get(gid);
! if (entry != null) {
return entry;
}
- }
throw new UnknownObjectException("object's group removed");
}
/**
* Container for group information: group's descriptor, group's
--- 698,781 ----
synchronized (Activation.this) {
shuttingDown = true;
}
// destroy all child processes (groups) quickly
for (GroupEntry groupEntry : groupTable.values()) {
groupEntry.shutdownFast();
}
}
}
/**
* Returns the groupID for a given id of an object in the group.
* Throws UnknownObjectException if the object is not registered.
*/
private ActivationGroupID getGroupID(ActivationID id)
throws UnknownObjectException
{
ActivationGroupID groupID = idTable.get(id);
if (groupID != null) {
return groupID;
}
throw new UnknownObjectException("unknown object: " + id);
}
/**
! * Returns the group entry for the group id, optionally removing it.
! * Throws UnknownGroupException if the group is not registered.
*/
! private GroupEntry getGroupEntry(ActivationGroupID id, boolean rm)
throws UnknownGroupException
{
if (id.getClass() == ActivationGroupID.class) {
! GroupEntry entry;
! if (rm) {
! entry = groupTable.remove(id);
! } else {
! entry = groupTable.get(id);
! }
if (entry != null && !entry.removed) {
return entry;
}
}
throw new UnknownGroupException("group unknown");
}
/**
+ * Returns the group entry for the group id. Throws
+ * UnknownGroupException if the group is not registered.
+ */
+ private GroupEntry getGroupEntry(ActivationGroupID id)
+ throws UnknownGroupException
+ {
+ return getGroupEntry(id, false);
+ }
+
+ /**
+ * Removes and returns the group entry for the group id. Throws
+ * UnknownGroupException if the group is not registered.
+ */
+ private GroupEntry removeGroupEntry(ActivationGroupID id)
+ throws UnknownGroupException
+ {
+ return getGroupEntry(id, true);
+ }
+
+ /**
* Returns the group entry for the object's id. Throws
* UnknownObjectException if the object is not registered or the
* object's group is not registered.
*/
private GroupEntry getGroupEntry(ActivationID id)
throws UnknownObjectException
{
ActivationGroupID gid = getGroupID(id);
GroupEntry entry = groupTable.get(gid);
! if (entry != null && !entry.removed) {
return entry;
}
throw new UnknownObjectException("object's group removed");
}
/**
* Container for group information: group's descriptor, group's
*** 880,892 ****
if (desc.getRestartMode() == true) {
restartSet.add(id);
}
// table insertion must take place before log update
- synchronized (idTable) {
idTable.put(id, groupID);
- }
if (addRecord) {
addLogRecord(new LogRegisterObject(id, desc));
}
}
--- 904,914 ----
*** 899,912 ****
objects.remove(id);
if (objEntry.desc.getRestartMode() == true) {
restartSet.remove(id);
}
! // table insertion must take place before log update
! synchronized (idTable) {
idTable.remove(id);
- }
if (addRecord) {
addLogRecord(new LogUnregisterObject(id));
}
}
--- 921,932 ----
objects.remove(id);
if (objEntry.desc.getRestartMode() == true) {
restartSet.remove(id);
}
! // table removal must take place before log update
idTable.remove(id);
if (addRecord) {
addLogRecord(new LogUnregisterObject(id));
}
}
*** 917,929 ****
removed = true;
for (Map.Entry<ActivationID,ObjectEntry> entry :
objects.entrySet())
{
ActivationID id = entry.getKey();
- synchronized (idTable) {
idTable.remove(id);
- }
ObjectEntry objEntry = entry.getValue();
objEntry.removed = true;
}
objects.clear();
restartSet.clear();
--- 937,947 ----