Apple sometimes hits the deadlock below while running the JCK in -Xcomp mode on a dual processor system during the JCK 1.4 api/java_awt/Toolkit/index.html#Cursor testcase.
The testcase fetches different images simultaneously using Toolkit.getImage(). This is a classic example of lock inversion deadlock.
Here is the relevant information:
FOUND A JAVA LEVEL DEADLOCK:
----------------------------
"Image Fetcher 3":
waiting to lock monitor 0x4bc44 (object 0x680067b0, a
sun.awt.image.GifImageDecoder),
which is locked by "Image Fetcher 1"
"Image Fetcher 1":
waiting to lock monitor 0x4bc1c (object 0x682dbeb8, a
sun.awt.image.URLImageSource),
which is locked by "Image Fetcher 3"
Here are the two threads in question:
Java Stack for "Image Fetcher 1":
==========
at
sun.awt.image.InputStreamImageSource.isConsumer(InputStreamImageSource.j
ava:111) <----waits on InputStreamImageSource lock
at sun.awt.image.PixelStore.replay(PixelStore.java:152)
at sun.awt.image.PixelStore.replay(PixelStore.java:144)
at
sun.awt.image.GifImageDecoder.catchupConsumer(GifImageDecoder.java:66)
<---- gets ImageDecoder lock
at
sun.awt.image.InputStreamImageSource.latchConsumers(InputStreamImageSour
ce.java:372)
at sun.awt.image.ImageDecoder.setPixels(ImageDecoder.java:102)
at sun.awt.image.GifImageDecoder.sendPixels(GifImageDecoder.java:458)
at sun.awt.image.GifImageDecoder.parseImage(Native Method)
at sun.awt.image.GifImageDecoder.readImage(GifImageDecoder.java:571)
at sun.awt.image.GifImageDecoder.produceImage(GifImageDecoder.java:218)
at
sun.awt.image.InputStreamImageSource.doFetch(InputStreamImageSource.java
:252)
at sun.awt.image.ImageFetcher.fetchloop(ImageFetcher.java:167)
at sun.awt.image.ImageFetcher.run(ImageFetcher.java:135)
GifImageDecoder.java:66
public synchronized boolean catchupConsumer(InputStreamImageSource
src, ImageConsumer ic)
{
return (cancatchup && (store == null || store.replay(src, ic)));
}
InputStreamImageSource.java:111
public synchronized boolean isConsumer(ImageConsumer ic) {
for (ImageDecoder id = decoders; id != null; id = id.next) {
if (id.isConsumer(ic)) {
return true;
}
}
return ImageConsumerQueue.isConsumer(consumers, ic);
}
Java Stack for "Image Fetcher 3":
==========
at sun.awt.image.ImageDecoder.close(ImageDecoder.java:161) <----waits
on ImageDecoder lock
at sun.awt.image.ImageDecoder.abort(ImageDecoder.java:150)
at sun.awt.image.ImageDecoder.removeConsumer(ImageDecoder.java:36)
at
sun.awt.image.InputStreamImageSource.removeConsumer(InputStreamImageSour
ce.java:135) <---- gets InputStreamImageSource lock
at
java.awt.image.FilteredImageSource.removeConsumer(FilteredImageSource.java:87)
at java.awt.image.PixelGrabber.imageComplete(PixelGrabber.java:599)
at java.awt.image.ImageFilter.imageComplete(ImageFilter.java:168)
at sun.awt.image.PixelStore.replay(PixelStore.java:224)
at sun.awt.image.PixelStore.replay(PixelStore.java:144)
at sun.awt.image.InputStreamImageSource.updateFromStore(InputStreamImageSou rce.java:286)
at
sun.awt.image.InputStreamImageSource.doFetch(InputStreamImageSource.java
:239)
at sun.awt.image.ImageFetcher.fetchloop(ImageFetcher.java:167)
at sun.awt.image.ImageFetcher.run(ImageFetcher.java:135)
InputStreamImageSource.java:135
public synchronized void removeConsumer(ImageConsumer ic) {
for (ImageDecoder id = decoders; id != null; id = id.next) {
id.removeConsumer(ic);
}
consumers = ImageConsumerQueue.removeConsumer(consumers, ic,
false);
if (consumers == null) {
stopProduction();
}
}
ImageDecoder.java:161
public synchronized void close() {
if (input != null) {
try {
input.close();
} catch (IOException e) {
}
}
}
The testcase fetches different images simultaneously using Toolkit.getImage(). This is a classic example of lock inversion deadlock.
Here is the relevant information:
FOUND A JAVA LEVEL DEADLOCK:
----------------------------
"Image Fetcher 3":
waiting to lock monitor 0x4bc44 (object 0x680067b0, a
sun.awt.image.GifImageDecoder),
which is locked by "Image Fetcher 1"
"Image Fetcher 1":
waiting to lock monitor 0x4bc1c (object 0x682dbeb8, a
sun.awt.image.URLImageSource),
which is locked by "Image Fetcher 3"
Here are the two threads in question:
Java Stack for "Image Fetcher 1":
==========
at
sun.awt.image.InputStreamImageSource.isConsumer(InputStreamImageSource.j
ava:111) <----waits on InputStreamImageSource lock
at sun.awt.image.PixelStore.replay(PixelStore.java:152)
at sun.awt.image.PixelStore.replay(PixelStore.java:144)
at
sun.awt.image.GifImageDecoder.catchupConsumer(GifImageDecoder.java:66)
<---- gets ImageDecoder lock
at
sun.awt.image.InputStreamImageSource.latchConsumers(InputStreamImageSour
ce.java:372)
at sun.awt.image.ImageDecoder.setPixels(ImageDecoder.java:102)
at sun.awt.image.GifImageDecoder.sendPixels(GifImageDecoder.java:458)
at sun.awt.image.GifImageDecoder.parseImage(Native Method)
at sun.awt.image.GifImageDecoder.readImage(GifImageDecoder.java:571)
at sun.awt.image.GifImageDecoder.produceImage(GifImageDecoder.java:218)
at
sun.awt.image.InputStreamImageSource.doFetch(InputStreamImageSource.java
:252)
at sun.awt.image.ImageFetcher.fetchloop(ImageFetcher.java:167)
at sun.awt.image.ImageFetcher.run(ImageFetcher.java:135)
GifImageDecoder.java:66
public synchronized boolean catchupConsumer(InputStreamImageSource
src, ImageConsumer ic)
{
return (cancatchup && (store == null || store.replay(src, ic)));
}
InputStreamImageSource.java:111
public synchronized boolean isConsumer(ImageConsumer ic) {
for (ImageDecoder id = decoders; id != null; id = id.next) {
if (id.isConsumer(ic)) {
return true;
}
}
return ImageConsumerQueue.isConsumer(consumers, ic);
}
Java Stack for "Image Fetcher 3":
==========
at sun.awt.image.ImageDecoder.close(ImageDecoder.java:161) <----waits
on ImageDecoder lock
at sun.awt.image.ImageDecoder.abort(ImageDecoder.java:150)
at sun.awt.image.ImageDecoder.removeConsumer(ImageDecoder.java:36)
at
sun.awt.image.InputStreamImageSource.removeConsumer(InputStreamImageSour
ce.java:135) <---- gets InputStreamImageSource lock
at
java.awt.image.FilteredImageSource.removeConsumer(FilteredImageSource.java:87)
at java.awt.image.PixelGrabber.imageComplete(PixelGrabber.java:599)
at java.awt.image.ImageFilter.imageComplete(ImageFilter.java:168)
at sun.awt.image.PixelStore.replay(PixelStore.java:224)
at sun.awt.image.PixelStore.replay(PixelStore.java:144)
at sun.awt.image.InputStreamImageSource.updateFromStore(InputStreamImageSou rce.java:286)
at
sun.awt.image.InputStreamImageSource.doFetch(InputStreamImageSource.java
:239)
at sun.awt.image.ImageFetcher.fetchloop(ImageFetcher.java:167)
at sun.awt.image.ImageFetcher.run(ImageFetcher.java:135)
InputStreamImageSource.java:135
public synchronized void removeConsumer(ImageConsumer ic) {
for (ImageDecoder id = decoders; id != null; id = id.next) {
id.removeConsumer(ic);
}
consumers = ImageConsumerQueue.removeConsumer(consumers, ic,
false);
if (consumers == null) {
stopProduction();
}
}
ImageDecoder.java:161
public synchronized void close() {
if (input != null) {
try {
input.close();
} catch (IOException e) {
}
}
}