OpenJDK / jdk8u / jdk8u / jdk
changeset 6317:46675076f753
7120365: DiffHBTest.java fails due to ConcurrentModificationException
Summary: The problem is from the server notification forwarder, it should use a copy of listener set to do iterate.
Reviewed-by: alanb
author | sjiang |
---|---|
date | Fri, 28 Dec 2012 16:44:27 +0100 |
parents | 4472a641b4dc |
children | ac5e29b62288 |
files | src/share/classes/com/sun/jmx/remote/internal/ServerNotifForwarder.java test/ProblemList.txt test/javax/management/remote/mandatory/notif/ConcurrentModificationTest.java |
diffstat | 3 files changed, 177 insertions(+), 9 deletions(-) [+] |
line wrap: on
line diff
--- a/src/share/classes/com/sun/jmx/remote/internal/ServerNotifForwarder.java Fri Dec 28 03:50:57 2012 -0800 +++ b/src/share/classes/com/sun/jmx/remote/internal/ServerNotifForwarder.java Fri Dec 28 16:44:27 2012 +0100 @@ -25,16 +25,15 @@ package com.sun.jmx.remote.internal; -import com.sun.jmx.mbeanserver.Util; import com.sun.jmx.remote.security.NotificationAccessController; import com.sun.jmx.remote.util.ClassLogger; import com.sun.jmx.remote.util.EnvHelp; import java.io.IOException; import java.security.AccessControlContext; import java.security.AccessController; -import java.security.PrivilegedAction; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; +import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -291,13 +290,18 @@ // so that we can know too, and remove the corresponding entry from the listenerMap. // See 6957378. private void snoopOnUnregister(NotificationResult nr) { - Set<IdAndFilter> delegateSet = listenerMap.get(MBeanServerDelegate.DELEGATE_NAME); - if (delegateSet == null || delegateSet.isEmpty()) { - return; + List<IdAndFilter> copy = null; + synchronized (listenerMap) { + Set<IdAndFilter> delegateSet = listenerMap.get(MBeanServerDelegate.DELEGATE_NAME); + if (delegateSet == null || delegateSet.isEmpty()) { + return; + } + copy = new ArrayList<>(delegateSet); } + for (TargetedNotification tn : nr.getTargetedNotifications()) { Integer id = tn.getListenerID(); - for (IdAndFilter idaf : delegateSet) { + for (IdAndFilter idaf : copy) { if (idaf.id == id) { // This is a notification from the MBeanServerDelegate. Notification n = tn.getNotification();
--- a/test/ProblemList.txt Fri Dec 28 03:50:57 2012 -0800 +++ b/test/ProblemList.txt Fri Dec 28 16:44:27 2012 +0100 @@ -148,9 +148,6 @@ # 6959636 javax/management/loading/LibraryLoader/LibraryLoaderTest.java windows-all -# 7120365 -javax/management/remote/mandatory/notif/DiffHBTest.java generic-all - ############################################################################ # jdk_math
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/javax/management/remote/mandatory/notif/ConcurrentModificationTest.java Fri Dec 28 16:44:27 2012 +0100 @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 7120365 + * @summary test on Concurrent Modification + * @author Shanliang JIANG + * @run main ConcurrentModificationTest + */ + +import java.net.MalformedURLException; +import java.util.ConcurrentModificationException; +import javax.management.MBeanServer; +import javax.management.MBeanServerConnection; +import javax.management.MBeanServerFactory; +import javax.management.Notification; +import javax.management.NotificationListener; +import javax.management.ObjectName; +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXConnectorFactory; +import javax.management.remote.JMXConnectorServer; +import javax.management.remote.JMXConnectorServerFactory; +import javax.management.remote.JMXServiceURL; + +/** + * + */ +public class ConcurrentModificationTest { + private static final String[] protocols = {"rmi", "iiop", "jmxmp"}; + private static int number = 100; + + private static final MBeanServer mbs = MBeanServerFactory.createMBeanServer(); + private static ObjectName delegateName; + private static ObjectName[] timerNames = new ObjectName[number]; + private static NotificationListener[] listeners = new NotificationListener[number]; + + private static Throwable uncaughtException = null; + + public static void main(String[] args) throws Exception { + System.out.println(">>> test on Concurrent Modification."); + + Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { + @Override + public void uncaughtException(Thread t, Throwable e) { + e.printStackTrace(); + if (e instanceof ConcurrentModificationException) { + uncaughtException = e; + } + } + }); + + delegateName = new ObjectName("JMImplementation:type=MBeanServerDelegate"); + for (int i=0; i<number; i++) { + timerNames[i] = new ObjectName("MBean:name=Timer"+i); + listeners[i] = new NotificationListener() { + @Override + public void handleNotification(Notification notification, Object handback) { + // nothing + } + }; + } + String errors = ""; + + for (int i = 0; i < protocols.length; i++) { + uncaughtException = null; + System.out.println(">>> Test for protocol " + protocols[i]); + test(protocols[i]); + if (uncaughtException != null) { + if ("".equals(errors)) { + errors = "Failed to " + protocols[i] + ": "+uncaughtException; + } else { + errors = errors+", failed to " + protocols[i] + ": "+uncaughtException; + } + System.out.println(">>> FAILED for protocol " + protocols[i]); + } else { + System.out.println(">>> PASSED for protocol " + protocols[i]); + } + } + + if ("".equals(errors)) { + System.out.println("All Passed!"); + } else { + System.out.println("!!!!!! Failed."); + + throw new RuntimeException(errors); + } + } + + private static void test(String proto) throws Exception { + JMXServiceURL u = new JMXServiceURL(proto, null, 0); + JMXConnectorServer server; + JMXConnector client; + + try { + server = + JMXConnectorServerFactory.newJMXConnectorServer(u, null, mbs); + server.start(); + JMXServiceURL addr = server.getAddress(); + client = JMXConnectorFactory.connect(addr, null); + } catch (MalformedURLException e) { + System.out.println(">>> not support: " + proto); + return; + } + + final MBeanServerConnection mserver = client.getMBeanServerConnection(); + + int count = 0; + boolean adding = true; + while (uncaughtException == null && count++ < 10) { + for (int i = 0; i < number; i++) { + listenerOp(mserver, listeners[i], adding); + mbeanOp(mserver, timerNames[i], adding); + } + adding = !adding; + } + + if (uncaughtException != null) { // clean + for (int i = 0; i < number; i++) { + try { + mbeanOp(mserver, timerNames[i], false); + } catch (Exception e) { + } + } + } + client.close(); + server.stop(); + } + + private static void mbeanOp(MBeanServerConnection mserver, ObjectName name, boolean adding) + throws Exception { + if (adding) { + mserver.createMBean("javax.management.timer.Timer", name); + } else { + mserver.unregisterMBean(name); + } + } + + private static void listenerOp(MBeanServerConnection mserver, NotificationListener listener, boolean adding) + throws Exception { + if (adding) { + mserver.addNotificationListener(delegateName, listener, null, null); + } else { + mserver.removeNotificationListener(delegateName, listener); + } + } +} \ No newline at end of file