# HG changeset patch # User jdv # Date 1454321342 -19800 # Node ID 3005aefa003ff4b005fcf38d4cda773e5f901626 # Parent 7f192a93c793c13423a2072a77fa5a440216e7bb 8022640: ServiceRegistry (used by ImageIO) lack synchronization Reviewed-by: prr, psadhukhan diff -r 7f192a93c793 -r 3005aefa003f jdk/src/java.desktop/share/classes/javax/imageio/spi/ServiceRegistry.java --- a/jdk/src/java.desktop/share/classes/javax/imageio/spi/ServiceRegistry.java Fri Jan 29 15:21:55 2016 +0530 +++ b/jdk/src/java.desktop/share/classes/javax/imageio/spi/ServiceRegistry.java Mon Feb 01 15:39:02 2016 +0530 @@ -759,7 +759,7 @@ this.category = category; } - public boolean registerServiceProvider(Object provider) { + public synchronized boolean registerServiceProvider(Object provider) { Object oprovider = map.get(provider.getClass()); boolean present = oprovider != null; @@ -781,7 +781,7 @@ * * @return true if the provider was previously registered. */ - public boolean deregisterServiceProvider(Object provider) { + public synchronized boolean deregisterServiceProvider(Object provider) { Object oprovider = map.get(provider.getClass()); if (provider == oprovider) { @@ -797,22 +797,23 @@ return false; } - public boolean contains(Object provider) { + public synchronized boolean contains(Object provider) { Object oprovider = map.get(provider.getClass()); return oprovider == provider; } - public boolean setOrdering(Object firstProvider, - Object secondProvider) { + public synchronized boolean setOrdering(Object firstProvider, + Object secondProvider) { return poset.setOrdering(firstProvider, secondProvider); } - public boolean unsetOrdering(Object firstProvider, - Object secondProvider) { + public synchronized boolean unsetOrdering(Object firstProvider, + Object secondProvider) { return poset.unsetOrdering(firstProvider, secondProvider); } - public Iterator getServiceProviders(boolean useOrdering) { + public synchronized Iterator getServiceProviders + (boolean useOrdering) { if (useOrdering) { return poset.iterator(); } else { @@ -821,11 +822,12 @@ } @SuppressWarnings("unchecked") - public T getServiceProviderByClass(Class providerClass) { + public synchronized T getServiceProviderByClass + (Class providerClass) { return (T)map.get(providerClass); } - public void clear() { + public synchronized void clear() { Iterator iter = map.values().iterator(); while (iter.hasNext()) { Object provider = iter.next(); @@ -839,7 +841,7 @@ poset.clear(); } - public void finalize() { + public synchronized void finalize() { clear(); } } diff -r 7f192a93c793 -r 3005aefa003f jdk/test/javax/imageio/spi/ServiceRegistrySyncTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/imageio/spi/ServiceRegistrySyncTest.java Mon Feb 01 15:39:02 2016 +0530 @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2016, 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 8022640 + * @summary Test verifies whether ServiceProvider API's of + * ServiceRegistry are safe for concurrent access. + * @run main ServiceRegistrySyncTest + */ + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Locale; +import javax.imageio.spi.ImageInputStreamSpi; +import javax.imageio.spi.ServiceRegistry; +import javax.imageio.stream.ImageInputStream; + +public class ServiceRegistrySyncTest { + public static void main(String[] args) throws InterruptedException { + + final ArrayList> services = new ArrayList>(); + services.add(ImageInputStreamSpi.class); + + final ServiceRegistry reg = new ServiceRegistry(services.iterator()); + + //create new thread for Registerer and Consumer Class + Thread registerer = new Thread(new Registerer(reg)); + Thread consumer = new Thread(new Consumer(reg)); + + //run both registerer and consumer thread parallely + registerer.start(); + consumer.start(); + } + + static class Consumer implements Runnable { + private final ServiceRegistry reg; + boolean go = true; + int duration; + long start, end; + + public Consumer(ServiceRegistry r) { + reg = r; + //set 5000ms duration to run the test + duration = 5000; + } + + @Override + public void run() { + start = System.currentTimeMillis(); + end = start + duration; + while (start < end) { + //access the ServiceProvider API + reg.getServiceProviders(ImageInputStreamSpi.class, true); + start = System.currentTimeMillis(); + } + } + } + + static class Registerer implements Runnable { + private final ServiceRegistry reg; + boolean go = true; + int duration; + long start, end; + + public Registerer(ServiceRegistry r) { + reg = r; + //set 5000ms duration to run the test + duration = 5000; + } + + @Override + public void run() { + final int N = 20; + + MyService[] services = new MyService[N]; + for (int i = 0; i < N; i++) { + services[i] = new MyService(); + } + start = System.currentTimeMillis(); + end = start + duration; + while (start < end) { + //access the ServiceProvider API's + for (int i = 0; i < N; i++) { + reg.registerServiceProvider(services[i]); + } + for (int i = 0; i < N; i++) { + reg.deregisterServiceProvider(services[i]); + } + start = System.currentTimeMillis(); + } + } + } +} + +class MyService extends ImageInputStreamSpi { + public MyService() { + } + + @Override + public String getDescription(Locale locale) { + return null; + } + + @Override + public ImageInputStream createInputStreamInstance + (Object input, boolean useCache, File cacheDir) throws IOException { + return null; + } +}