Hi,

This solves a gdk lockup in GdkPixbufWriter by implementing the
suggestion in the FIXME. Now we don't drop and re-acquire the gdk-lock
but store the data and push that to the user code from a separate
thread.

2006-06-11  Mark Wielaard  <[EMAIL PROTECTED]>

        * gnu/java/awt/peer/gtk/GdkPixbufDecoder.java (streamImage):
        Takes GdkPixbufWriter.
        (GdkPixbufWriter): Implements Runnable.
        (write(IIOMetadata,IIOImage,ImageWriteParam)): Start Thread for
        data processing.
        (DATADONE): New static final field.
        (data): New field.
        (write(byte[])): New method.
        (run): Likewise.
        * native/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkPixbufDecoder.c
        (Java_gnu_java_awt_peer_gtk_GdkPixbufDecoder_initStaticState):
        Get dataOutputWriteID from writeClass.
        (stream_save_request): Change stream field to writer.
        (save_to_stream): Remove FIXME, call writer.
        (Java_gnu_java_awt_peer_gtk_GdkPixbufDecoder_streamImage):
        Store writer.

This solves the niffler deadlock we were seeing described in bug #27917.

Committed,

Mark
Index: gnu/java/awt/peer/gtk/GdkPixbufDecoder.java
===================================================================
RCS file: /cvsroot/classpath/classpath/gnu/java/awt/peer/gtk/GdkPixbufDecoder.java,v
retrieving revision 1.22
diff -u -r1.22 GdkPixbufDecoder.java
--- gnu/java/awt/peer/gtk/GdkPixbufDecoder.java	30 May 2006 22:36:32 -0000	1.22
+++ gnu/java/awt/peer/gtk/GdkPixbufDecoder.java	11 Jun 2006 21:46:03 -0000
@@ -103,8 +103,15 @@
   native void pumpBytes (byte[] bytes, int len) throws IOException;
   native void pumpDone () throws IOException;
   native void finish (boolean needsClose);
-  static native void streamImage(int[] bytes, String format, int width, int height, boolean hasAlpha, DataOutput sink);
-  
+
+  /**
+   * Converts given image to bytes.
+   * Will call the GdkPixbufWriter for each chunk.
+   */
+  static native void streamImage(int[] bytes, String format,
+                                 int width, int height,
+                                 boolean hasAlpha, GdkPixbufWriter writer);
+
   // gdk-pixbuf provids data in RGBA format
   static final ColorModel cm = new DirectColorModel (32, 0xff000000, 
                                                      0x00ff0000, 
@@ -461,7 +468,7 @@
   }
 
   private static class GdkPixbufWriter
-    extends ImageWriter
+    extends ImageWriter implements Runnable
   {
     String ext;
     public GdkPixbufWriter(GdkPixbufWriterSpi ownerSpi, Object ext)
@@ -519,14 +526,80 @@
           model = img.getColorModel();
         }
 
+      new Thread(this, "GdkPixbufWriter").start();
       processImageStarted(1);
       synchronized(pixbufLock)
 	{
 	  streamImage(pixels, this.ext, width, height, model.hasAlpha(), 
-		      (DataOutput) this.getOutput());
+		      this);
 	}
-      processImageComplete();
+      synchronized(data)
+        {
+          data.add(DATADONE);
+        }
     }    
+
+    /**
+     * Object marking end of data from native streamImage code.
+     */
+    private static final Object DATADONE = new Object();
+
+    /**
+     * Holds the data gotten from the native streamImage code.
+     * A worker thread will pull data out.
+     * Needs to be synchronized for access.
+     * The special object DATADONE is added when all data has been delivered.
+     */
+    private ArrayList data = new ArrayList();
+
+    /** Callback for streamImage native code. **/
+    private void write(byte[] bs)
+    {
+      synchronized(data)
+        {
+          data.add(bs);
+          data.notifyAll();
+        }
+    }
+
+    public void run()
+    {
+      boolean done = false;
+      while (!done)
+        {
+          synchronized(data)
+            {
+              while (data.isEmpty())
+                {
+                  try
+                    {
+                      data.wait();
+                    }
+                  catch (InterruptedException ie)
+                    {
+                      /* ignore */
+                    }
+                }
+
+              Object o = data.remove(0);
+              if (o == DATADONE)
+                done = true;
+              else
+                {
+                  DataOutput out = (DataOutput) getOutput();
+                  try
+                    {
+                      out.write((byte[]) o);
+                    }
+                  catch (IOException ioe)
+                    {
+                      // Not much we can do now...
+                    }
+                }
+            }
+        }
+      processImageComplete();
+    }
   }
 
   private static class GdkPixbufReader 
Index: native/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkPixbufDecoder.c
===================================================================
RCS file: /cvsroot/classpath/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkPixbufDecoder.c,v
retrieving revision 1.22
diff -u -r1.22 gnu_java_awt_peer_gtk_GdkPixbufDecoder.c
--- native/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkPixbufDecoder.c	20 Mar 2006 14:42:37 -0000	1.22
+++ native/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkPixbufDecoder.c	11 Jun 2006 21:46:09 -0000
@@ -278,7 +278,7 @@
 Java_gnu_java_awt_peer_gtk_GdkPixbufDecoder_initStaticState 
   (JNIEnv *env, jclass clazz)
 {
-  jclass dataOutputClass;
+  jclass writerClass;
 
   (*env)->GetJavaVM(env, &vm);
 
@@ -296,9 +296,9 @@
      "(Ljava/lang/String;Z)"
      "Lgnu/java/awt/peer/gtk/GdkPixbufDecoder$ImageFormatSpec;");
 
-  
-  dataOutputClass = (*env)->FindClass(env, "java/io/DataOutput");
-  dataOutputWriteID = (*env)->GetMethodID (env, dataOutputClass,
+  writerClass = (*env)->FindClass
+    (env, "gnu/java/awt/peer/gtk/GdkPixbufDecoder$GdkPixbufWriter");
+  dataOutputWriteID = (*env)->GetMethodID (env, writerClass,
 					     "write", "([B)V");
 
   query_formats (env, clazz);
@@ -344,7 +344,7 @@
 struct stream_save_request
 {
   JNIEnv *env;
-  jobject *stream;
+  jobject *writer;
 };
 
 static gboolean
@@ -358,30 +358,23 @@
   jbyteArray jbuf;
   jbyte *cbuf;
 
-  /* FIXME. Don't call user code directly on this thread.
-     Store bytes and signal a "pump" thread to deliver to user code.
-     Then we don't have to drop/acquire any locks. */
-  gdk_threads_leave ();
-
   jbuf = (*(ssr->env))->NewByteArray ((ssr->env), count);
   cbuf = (*(ssr->env))->GetByteArrayElements ((ssr->env), jbuf, NULL);
   memcpy (cbuf, buf, count);
   (*(ssr->env))->ReleaseByteArrayElements ((ssr->env), jbuf, cbuf, 0);
-  (*(ssr->env))->CallVoidMethod ((ssr->env), *(ssr->stream), 
+  (*(ssr->env))->CallVoidMethod ((ssr->env), *(ssr->writer), 
 				 dataOutputWriteID, jbuf);  
   (*(ssr->env))->DeleteLocalRef((ssr->env), jbuf);
 
-  gdk_threads_enter ();
-
   return TRUE;
 }
 
 
 JNIEXPORT void JNICALL
 Java_gnu_java_awt_peer_gtk_GdkPixbufDecoder_streamImage
-(JNIEnv *env, jclass clazz __attribute__((unused)), 
+(JNIEnv *env, jclass clazz __attribute__((unused)),
  jintArray jarr, jstring jenctype, jint width, jint height, 
- jboolean hasAlpha, jobject stream)
+ jboolean hasAlpha, jobject writer) 
 {
   GdkPixbuf* pixbuf;  
   jint *ints;
@@ -391,7 +384,7 @@
   int i;
   struct stream_save_request ssr;
 
-  ssr.stream = &stream;
+  ssr.writer = &writer;
   ssr.env = env;
 
   ints = (*env)->GetIntArrayElements (env, jarr, NULL);

Attachment: signature.asc
Description: This is a digitally signed message part

Reply via email to