6986863: ProfileDeferralMgr throwing ConcurrentModificationException

Reviewed-by: kizune
This commit is contained in:
Sergey Bylokhov 2021-01-29 06:18:43 +00:00
parent ea2c4474be
commit 64a150c518
9 changed files with 256 additions and 338 deletions

@ -55,10 +55,8 @@ import java.util.StringTokenizer;
import sun.java2d.cmm.CMSManager;
import sun.java2d.cmm.PCMM;
import sun.java2d.cmm.Profile;
import sun.java2d.cmm.ProfileActivator;
import sun.java2d.cmm.ProfileDataVerifier;
import sun.java2d.cmm.ProfileDeferralInfo;
import sun.java2d.cmm.ProfileDeferralMgr;
/**
* A representation of color profile data for device independent and device
@ -93,10 +91,8 @@ public class ICC_Profile implements Serializable {
@Serial
private static final long serialVersionUID = -3938515861990936766L;
private transient Profile cmmProfile;
private transient ProfileDeferralInfo deferralInfo;
private transient ProfileActivator profileActivator;
private transient volatile Profile cmmProfile;
private transient volatile ProfileDeferralInfo deferralInfo;
// Registry of singleton profile objects for specific color spaces
// defined in the ColorSpace class (e.g. CS_sRGB), see
@ -731,7 +727,7 @@ public class ICC_Profile implements Serializable {
* Constructs an {@code ICC_Profile} object with a given ID.
*/
ICC_Profile(Profile p) {
this.cmmProfile = p;
cmmProfile = p;
}
/**
@ -739,13 +735,7 @@ public class ICC_Profile implements Serializable {
* The ID will be 0 until the profile is loaded.
*/
ICC_Profile(ProfileDeferralInfo pdi) {
this.deferralInfo = pdi;
this.profileActivator = new ProfileActivator() {
public void activate() throws ProfileDataException {
activateDeferredProfile();
}
};
ProfileDeferralMgr.registerDeferral(this.profileActivator);
deferralInfo = pdi;
}
/**
@ -780,10 +770,6 @@ public class ICC_Profile implements Serializable {
Profile p = null;
if (ProfileDeferralMgr.deferring) {
ProfileDeferralMgr.activateProfiles();
}
ProfileDataVerifier.verify(data);
try {
@ -842,11 +828,11 @@ public class ICC_Profile implements Serializable {
* Enabling the appropriate access privileges is handled
* at a lower level.
*/
ProfileDeferralInfo pInfo =
ProfileDeferralInfo pdi =
new ProfileDeferralInfo("sRGB.pf",
ColorSpace.TYPE_RGB, 3,
CLASS_DISPLAY);
sRGBprofile = getDeferredInstance(pInfo);
sRGBprofile = new ICC_ProfileRGB(pdi);
}
thisProfile = sRGBprofile;
}
@ -856,11 +842,11 @@ public class ICC_Profile implements Serializable {
case ColorSpace.CS_CIEXYZ:
synchronized(ICC_Profile.class) {
if (XYZprofile == null) {
ProfileDeferralInfo pInfo =
ProfileDeferralInfo pdi =
new ProfileDeferralInfo("CIEXYZ.pf",
ColorSpace.TYPE_XYZ, 3,
CLASS_ABSTRACT);
XYZprofile = getDeferredInstance(pInfo);
XYZprofile = new ICC_Profile(pdi);
}
thisProfile = XYZprofile;
}
@ -870,11 +856,11 @@ public class ICC_Profile implements Serializable {
case ColorSpace.CS_PYCC:
synchronized(ICC_Profile.class) {
if (PYCCprofile == null) {
ProfileDeferralInfo pInfo =
ProfileDeferralInfo pdi =
new ProfileDeferralInfo("PYCC.pf",
ColorSpace.TYPE_3CLR, 3,
CLASS_COLORSPACECONVERSION);
PYCCprofile = getDeferredInstance(pInfo);
PYCCprofile = new ICC_Profile(pdi);
}
thisProfile = PYCCprofile;
}
@ -884,11 +870,11 @@ public class ICC_Profile implements Serializable {
case ColorSpace.CS_GRAY:
synchronized(ICC_Profile.class) {
if (GRAYprofile == null) {
ProfileDeferralInfo pInfo =
ProfileDeferralInfo pdi =
new ProfileDeferralInfo("GRAY.pf",
ColorSpace.TYPE_GRAY, 1,
CLASS_DISPLAY);
GRAYprofile = getDeferredInstance(pInfo);
GRAYprofile = new ICC_ProfileGray(pdi);
}
thisProfile = GRAYprofile;
}
@ -898,11 +884,11 @@ public class ICC_Profile implements Serializable {
case ColorSpace.CS_LINEAR_RGB:
synchronized(ICC_Profile.class) {
if (LINEAR_RGBprofile == null) {
ProfileDeferralInfo pInfo =
ProfileDeferralInfo pdi =
new ProfileDeferralInfo("LINEAR_RGB.pf",
ColorSpace.TYPE_RGB, 3,
CLASS_DISPLAY);
LINEAR_RGBprofile = getDeferredInstance(pInfo);
LINEAR_RGBprofile = new ICC_ProfileRGB(pdi);
}
thisProfile = LINEAR_RGBprofile;
}
@ -916,26 +902,6 @@ public class ICC_Profile implements Serializable {
return thisProfile;
}
/**
* This method asserts system privileges, so is used only for the standard
* profiles.
*/
private static ICC_Profile getStandardProfile(final String name) {
return AccessController.doPrivileged(
new PrivilegedAction<ICC_Profile>() {
public ICC_Profile run() {
ICC_Profile p = null;
try {
p = getInstance(name);
} catch (IOException ex) {
throw new IllegalArgumentException(
"Can't load standard profile: " + name);
}
return p;
}
});
}
/**
* Constructs an {@code ICC_Profile} corresponding to the data in a file.
* {@code fileName} may be an absolute or a relative file specification.
@ -997,13 +963,7 @@ public class ICC_Profile implements Serializable {
* Profile data
*/
public static ICC_Profile getInstance(InputStream s) throws IOException {
byte[] profileData;
if (s instanceof ProfileDeferralInfo) {
/* hack to detect profiles whose loading can be deferred */
return getDeferredInstance((ProfileDeferralInfo) s);
}
byte[] profileData;
if ((profileData = getProfileDataFromStream(s)) == null) {
throw new IllegalArgumentException("Invalid ICC Profile Data");
}
@ -1035,61 +995,32 @@ public class ICC_Profile implements Serializable {
}
/**
* Constructs an {@code ICC_Profile} for which the actual loading of the
* profile data from a file and the initialization of the CMM should be
* deferred as long as possible. Deferral is only used for standard
* profiles. If deferring is disabled, then getStandardProfile() ensures
* that all of the appropriate access privileges are granted when loading
* this profile. If deferring is enabled, then the deferred activation code
* will take care of access privileges.
*
* @see #activateDeferredProfile()
* Activates the deferred standard profiles. Implementation of this method
* mimics the old behaviour when the CMMException and IOException were
* wrapped by the ProfileDataException, and the ProfileDataException itself
* was ignored during activation.
*/
static ICC_Profile getDeferredInstance(ProfileDeferralInfo pdi) {
if (!ProfileDeferralMgr.deferring) {
return getStandardProfile(pdi.filename);
}
if (pdi.colorSpaceType == ColorSpace.TYPE_RGB) {
return new ICC_ProfileRGB(pdi);
} else if (pdi.colorSpaceType == ColorSpace.TYPE_GRAY) {
return new ICC_ProfileGray(pdi);
} else {
return new ICC_Profile(pdi);
}
}
void activateDeferredProfile() throws ProfileDataException {
byte[] profileData;
final String fileName = deferralInfo.filename;
profileActivator = null;
deferralInfo = null;
InputStream is = getStandardProfileInputStream(fileName);
if (is == null) {
throw new ProfileDataException("Cannot open file " + fileName);
}
try {
profileData = getProfileDataFromStream(is);
is.close(); /* close the file */
}
catch (IOException e) {
ProfileDataException pde = new
ProfileDataException("Invalid ICC Profile Data" + fileName);
pde.initCause(e);
throw pde;
}
if (profileData == null) {
throw new ProfileDataException("Invalid ICC Profile Data" +
fileName);
}
try {
cmmProfile = CMSManager.getModule().loadProfile(profileData);
} catch (CMMException c) {
ProfileDataException pde = new
ProfileDataException("Invalid ICC Profile Data" + fileName);
pde.initCause(c);
throw pde;
private void activate() {
if (cmmProfile == null) {
synchronized (this) {
if (cmmProfile != null) {
return;
}
var is = getStandardProfileInputStream(deferralInfo.filename);
if (is == null) {
return;
}
try {
byte[] data = getProfileDataFromStream(is);
if (data != null) {
cmmProfile = CMSManager.getModule().loadProfile(data);
// from now we cannot use the deferred value, drop it
deferralInfo = null;
}
is.close(); /* close the stream */
} catch (CMMException | IOException ignore) {
}
}
}
}
@ -1130,11 +1061,9 @@ public class ICC_Profile implements Serializable {
byte[] theHeader;
int theClassSig, theClass;
if (deferralInfo != null) {
return deferralInfo.profileClass; /* Need to have this info for
ICC_ColorSpace without
causing a deferred profile
to be loaded */
ProfileDeferralInfo info = deferralInfo;
if (info != null) {
return info.profileClass;
}
theHeader = getData(icSigHead);
@ -1190,12 +1119,11 @@ public class ICC_Profile implements Serializable {
* {@code ColorSpace} class
*/
public int getColorSpaceType() {
if (deferralInfo != null) {
return deferralInfo.colorSpaceType; /* Need to have this info for
ICC_ColorSpace without
causing a deferred profile
to be loaded */
ProfileDeferralInfo info = deferralInfo;
if (info != null) {
return info.colorSpaceType;
}
activate();
return getColorSpaceType(cmmProfile);
}
@ -1223,9 +1151,7 @@ public class ICC_Profile implements Serializable {
* {@code ColorSpace} class
*/
public int getPCSType() {
if (ProfileDeferralMgr.deferring) {
ProfileDeferralMgr.activateProfiles();
}
activate();
return getPCSType(cmmProfile);
}
@ -1283,9 +1209,7 @@ public class ICC_Profile implements Serializable {
int profileSize;
byte[] profileData;
if (ProfileDeferralMgr.deferring) {
ProfileDeferralMgr.activateProfiles();
}
activate();
PCMM mdl = CMSManager.getModule();
@ -1315,9 +1239,7 @@ public class ICC_Profile implements Serializable {
*/
public byte[] getData(int tagSignature) {
if (ProfileDeferralMgr.deferring) {
ProfileDeferralMgr.activateProfiles();
}
activate();
return getData(cmmProfile, tagSignature);
}
@ -1363,9 +1285,7 @@ public class ICC_Profile implements Serializable {
*/
public void setData(int tagSignature, byte[] tagData) {
if (ProfileDeferralMgr.deferring) {
ProfileDeferralMgr.activateProfiles();
}
activate();
CMSManager.getModule().setTagData(cmmProfile, tagSignature, tagData);
}
@ -1417,11 +1337,9 @@ public class ICC_Profile implements Serializable {
byte[] theHeader;
int theColorSpaceSig, theNumComponents;
if (deferralInfo != null) {
return deferralInfo.numComponents; /* Need to have this info for
ICC_ColorSpace without
causing a deferred profile
to be loaded */
ProfileDeferralInfo info = deferralInfo;
if (info != null) {
return info.numComponents;
}
theHeader = getData(icSigHead);

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2021, 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
@ -36,16 +36,18 @@
package java.awt.image;
import java.awt.Point;
import java.awt.Graphics2D;
import java.awt.color.*;
import sun.java2d.cmm.ColorTransform;
import sun.java2d.cmm.CMSManager;
import sun.java2d.cmm.ProfileDeferralMgr;
import sun.java2d.cmm.PCMM;
import java.awt.geom.Rectangle2D;
import java.awt.geom.Point2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.color.ColorSpace;
import java.awt.color.ICC_ColorSpace;
import java.awt.color.ICC_Profile;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import sun.java2d.cmm.CMSManager;
import sun.java2d.cmm.ColorTransform;
import sun.java2d.cmm.PCMM;
/**
* This class performs a pixel-by-pixel color conversion of the data in
@ -77,13 +79,6 @@ public class ColorConvertOp implements BufferedImageOp, RasterOp {
boolean gotProfiles;
float[] srcMinVals, srcMaxVals, dstMinVals, dstMaxVals;
/* the class initializer */
static {
if (ProfileDeferralMgr.deferring) {
ProfileDeferralMgr.activateProfiles();
}
}
/**
* Constructs a new ColorConvertOp which will convert
* from a source color space to a destination color space.

@ -1,41 +0,0 @@
/*
* Copyright (c) 1998, 2006, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package sun.java2d.cmm;
import java.awt.color.ProfileDataException;
/**
* An interface to allow the ProfileDeferralMgr to activate a
* deferred profile.
*/
public interface ProfileActivator {
/**
* Activate a previously deferred ICC_Profile object.
*/
public void activate() throws ProfileDataException;
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2021, 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
@ -25,37 +25,28 @@
package sun.java2d.cmm;
import java.io.InputStream;
import java.io.IOException;
/**
* A class to pass information about a profile to be loaded from
* a file to the static getInstance(InputStream) method of
* ICC_Profile. Loading of the profile data and initialization
* of the CMM is to be deferred as long as possible.
* A class to pass information about a profile to be loaded from a file to the
* static getInstance(int cspace) method of ICC_Profile. Loading of the profile
* data and initialization of the CMM is to be deferred as long as possible.
*/
public class ProfileDeferralInfo extends InputStream {
public final class ProfileDeferralInfo {
public int colorSpaceType, numComponents, profileClass;
public String filename;
/**
* Need to have this info for ICC_ColorSpace without causing a deferred
* profile to be loaded.
*/
public final int colorSpaceType, numComponents, profileClass;
/**
* The profile file name, such as "CIEXYZ.pf", "sRGB.pf", etc.
*/
public final String filename;
public ProfileDeferralInfo(String fn, int type, int ncomp, int pclass) {
super();
filename = fn;
colorSpaceType = type;
numComponents = ncomp;
profileClass = pclass;
}
/**
* Implements the abstract read() method of InputStream.
*/
public int read() throws IOException {
return 0;
}
}

@ -1,102 +0,0 @@
/*
* Copyright (c) 1998, 2020, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package sun.java2d.cmm;
import java.awt.color.ProfileDataException;
import java.util.Vector;
/**
* A class to manage the deferral of CMM initialization of profile
* data for internal ICC_Profile objects - i.e. when we "trust" that
* the profile data is valid and we think it may not be needed. An
* example is the sRGB profile which gets loaded by any program doing
* graphics, but which may not be needed if the program does not need
* high quality color conversion.
*/
public class ProfileDeferralMgr {
public static boolean deferring = true;
private static Vector<ProfileActivator> aVector;
/**
* Records a ProfileActivator object whose activate method will
* be called if the CMM needs to be activated.
*/
public static void registerDeferral(ProfileActivator pa) {
if (!deferring) {
return;
}
if (aVector == null) {
aVector = new Vector<ProfileActivator>(3, 3);
}
aVector.addElement(pa);
return;
}
/**
* Removes a ProfileActivator object from the vector of ProfileActivator
* objects whose activate method will be called if the CMM needs to be
* activated.
*/
public static void activateProfiles() {
int i, n;
deferring = false;
if (aVector == null) {
return;
}
n = aVector.size();
for (ProfileActivator pa : aVector) {
try {
pa.activate();
} catch (ProfileDataException e) {
/*
* Ignore profile activation error for now:
* such exception is pssible due to absence
* or corruption of standard color profile.
* As for now we expect all profiles should
* be shiped with jre and presence of this
* exception is indication of some configuration
* problem in jre installation.
*
* NB: we still are greedy loading deferred profiles
* and load them all if any of them is needed.
* Therefore broken profile (if any) might be never used.
* If there will be attempt to use broken profile then
* it will result in CMMException.
*/
}
}
aVector.removeAllElements();
aVector = null;
return;
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2007, 2021, 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
@ -35,19 +35,19 @@
package sun.java2d.cmm.lcms;
import java.awt.color.ICC_Profile;
import java.awt.color.CMMException;
import java.awt.color.ColorSpace;
import java.awt.color.ICC_Profile;
import java.awt.image.BufferedImage;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import java.awt.image.ColorModel;
import java.awt.image.SampleModel;
import java.awt.image.DataBuffer;
import sun.java2d.cmm.*;
import sun.java2d.cmm.lcms.*;
import static sun.java2d.cmm.lcms.LCMSImageLayout.ImageLayoutException;
import java.awt.image.Raster;
import java.awt.image.SampleModel;
import java.awt.image.WritableRaster;
import sun.java2d.cmm.ColorTransform;
import static sun.java2d.cmm.lcms.LCMSImageLayout.ImageLayoutException;
public class LCMSTransform implements ColorTransform {
long ID;
@ -66,13 +66,6 @@ public class LCMSTransform implements ColorTransform {
private Object disposerReferent = new Object();
/* the class initializer */
static {
if (ProfileDeferralMgr.deferring) {
ProfileDeferralMgr.activateProfiles();
}
}
public LCMSTransform(ICC_Profile profile, int renderType,
int transformType)
{

@ -1,5 +1,5 @@
/*
* Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2007, 2021, 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
@ -649,9 +649,22 @@ JNIEXPORT jobject JNICALL Java_sun_java2d_cmm_lcms_LCMS_getProfileID
if (pf == NULL) {
return NULL;
}
fid = (*env)->GetFieldID (env,
(*env)->GetObjectClass(env, pf),
"cmmProfile", "Lsun/java2d/cmm/Profile;");
jclass pcls = (*env)->GetObjectClass(env, pf);
if (pcls == NULL) {
return NULL;
}
jmethodID mid = (*env)->GetMethodID(env, pcls, "activate", "()V");
if (mid == NULL) {
return NULL;
}
(*env)->CallVoidMethod(env, pf, mid);
if ((*env)->ExceptionOccurred(env)) {
return NULL;
}
fid = (*env)->GetFieldID(env, pcls, "cmmProfile",
"Lsun/java2d/cmm/Profile;");
if (fid == NULL) {
return NULL;
}

@ -0,0 +1,72 @@
/*
* Copyright (c) 2021, 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.
*/
import java.awt.color.ColorSpace;
import java.awt.color.ICC_Profile;
import java.awt.color.ICC_ProfileRGB;
import java.util.concurrent.CountDownLatch;
/**
* @test
* @bug 6986863
* @summary Verifies MT safety of ICC_ProfileRGB#getMatrix method
*/
public final class MTMatrixAccess {
private static volatile boolean failed;
public static void main(String[] args) throws Exception {
test((ICC_ProfileRGB) ICC_Profile.getInstance(ColorSpace.CS_sRGB));
test((ICC_ProfileRGB) ICC_Profile.getInstance(ColorSpace.CS_LINEAR_RGB));
}
private static void test(ICC_ProfileRGB rgb) throws InterruptedException {
Thread[] threads = new Thread[100];
CountDownLatch go = new CountDownLatch(1);
for (int i = 0; i < threads.length; i++) {
threads[i] = new Thread(() -> {
try {
go.await();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
try {
rgb.getMatrix();
} catch (Throwable t) {
t.printStackTrace();
failed = true;
}
});
}
for (Thread thread : threads) {
thread.start();
}
go.countDown();
for (Thread thread : threads) {
thread.join();
}
if (failed) {
throw new RuntimeException();
}
}
}

@ -0,0 +1,79 @@
/*
* Copyright (c) 2021, 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.
*/
import java.awt.color.ColorSpace;
import java.awt.color.ICC_Profile;
import java.util.concurrent.CountDownLatch;
/**
* @test
* @bug 6986863
* @summary Verifies MT safety of profile activation while a profile is accessed
*/
public final class ProfileActivationDuringPropertyAccess {
private static volatile boolean failed;
private static volatile boolean end;
public static void main(String[] args) throws Exception {
test(ICC_Profile.getInstance(ColorSpace.CS_sRGB));
test(ICC_Profile.getInstance(ColorSpace.CS_GRAY));
test(ICC_Profile.getInstance(ColorSpace.CS_CIEXYZ));
test(ICC_Profile.getInstance(ColorSpace.CS_LINEAR_RGB));
test(ICC_Profile.getInstance(ColorSpace.CS_PYCC));
}
private static void test(ICC_Profile profile) throws Exception {
Thread[] ts = new Thread[100];
CountDownLatch latch = new CountDownLatch(ts.length);
for (int i = 0; i < ts.length; i++) {
ts[i] = new Thread(() -> {
latch.countDown();
try {
latch.await();
} catch (InterruptedException ex) {
}
try {
while (!end) {
profile.getColorSpaceType(); // try use deferred info
}
} catch (Throwable t) {
t.printStackTrace();
failed = true;
}
});
}
for (Thread t : ts) {
t.start();
}
Thread.sleep(1500);
profile.getPCSType(); // activate profile
end = true;
for (Thread t : ts) {
t.join();
}
if (failed) {
throw new RuntimeException();
}
}
}