changeset 2254:c764b38139a5

PR556: Re-implement applet initialization to be serialialized, to fix current and future possible race conditions.
author Deepak Bhole <dbhole@redhat.com>
date Thu, 16 Sep 2010 13:03:57 -0400
parents 1c5acca8abfd
children a1ccc755c8f7
files ChangeLog NEWS plugin/icedteanp/IcedTeaJavaRequestProcessor.h plugin/icedteanp/IcedTeaNPPlugin.cc plugin/icedteanp/IcedTeaNPPlugin.h plugin/icedteanp/IcedTeaPluginUtils.cc plugin/icedteanp/java/sun/applet/PluginAppletViewer.java plugin/icedteanp/java/sun/applet/PluginMessageConsumer.java
diffstat 8 files changed, 234 insertions(+), 317 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Mon Sep 13 10:21:58 2010 -0400
+++ b/ChangeLog	Thu Sep 16 13:03:57 2010 -0400
@@ -1,3 +1,44 @@
+2010-09-15  Deepak Bhole <dbhole@redhat.com>
+
+	PR556: Re-implement applet initialization to be serialialized, to fix 
+	current and	future possible race conditions.
+	* plugin/icedteanp/IcedTeaJavaRequestProcessor.h: Updated timeout to 3
+	minutes.
+	* plugin/icedteanp/IcedTeaNPPlugin.cc
+	(ITNP_New): Remove the tag_message string, don't send any data to Java
+	side and instead, populate the new ITNPPluginData.applet_tag field with
+	the tag info. Do cleanup accordingly.
+	(ITNP_SetWindow): Send all (handle, size and tag) initialization 
+	information to java in a single message. Cleanup accordingly for newly
+	added variables.
+	* plugin/icedteanp/IcedTeaPluginUtils.cc
+	(getReference): Use a negative decreasing reference count to prevent
+	clashes with references for Java-side requests.
+	* plugin/icedteanp/IcedTeaNPPlugin.h: Rename the instance_string field of
+	ITNPPluginData to instance_id, and add an applet_tag field.
+	* plugin/icedteanp/java/sun/applet/PluginAppletViewer.java
+	(PluginAppletPanelFactory.createPanel): Remove code that tried to account
+	for percent heights and widths. This is done by the browser now.
+	(reFrame): Same.
+	(PluginAppletViewer): Update constructor to not take height and width
+	factor information.
+	(handleMessage): Update function for new protocol that now passes all
+	information relevant to initialization in a single message.
+	(skipSpace): Accept a new int array that contains the character at the
+	current position in the stream. Use the value accordingly.
+	(scanIdentifier): Same.
+	(skipComment): Same.
+	(scanTag): Same.
+	(parse): Updated all function signatures to accept width and height info.
+	Initialize an int array (for fake pass-by-reference) that contains
+	position of current character in the stream. Inject width and height
+	information into the atts table.
+	* plugin/icedteanp/java/sun/applet/PluginMessageConsumer.java: Updated
+	thread count needed for initialization.
+	(okayToProcess): Remove function that is no longer needed with the
+	serialized initialization code.
+	(ConsumerThread.run): Remove call to okayToProcess().
+
 2010-09-13  Omair Majid  <omajid@redhat.com>
 
 	Add a new man page for netx's javaws.
--- a/NEWS	Mon Sep 13 10:21:58 2010 -0400
+++ b/NEWS	Thu Sep 16 13:03:57 2010 -0400
@@ -16,6 +16,8 @@
   - S6438179: XToolkit.isTraySupported() result has nothing to do with the system tray
 * Netx
   - A new man page for javaws.
+* Plugin  
+  - PR556: Applet initialization code is prone to race conditions
 
 New in release 1.9 (2010-09-07):
 
--- a/plugin/icedteanp/IcedTeaJavaRequestProcessor.h	Mon Sep 13 10:21:58 2010 -0400
+++ b/plugin/icedteanp/IcedTeaJavaRequestProcessor.h	Thu Sep 16 13:03:57 2010 -0400
@@ -46,7 +46,7 @@
 #include "IcedTeaNPPlugin.h"
 #include "IcedTeaPluginUtils.h"
 
-#define REQUESTTIMEOUT 120
+#define REQUESTTIMEOUT 180
 
 /*
  * This struct holds data specific to a Java operation requested by the plugin
--- a/plugin/icedteanp/IcedTeaNPPlugin.cc	Mon Sep 13 10:21:58 2010 -0400
+++ b/plugin/icedteanp/IcedTeaNPPlugin.cc	Thu Sep 16 13:03:57 2010 -0400
@@ -249,7 +249,7 @@
 
 // Creates a new icedtea np plugin instance.  This function creates a
 // ITNPPluginData* and stores it in instance->pdata.  The following
-// ITNPPluginData fiels are initialized: instance_string, in_pipe_name,
+// ITNPPluginData fiels are initialized: instance_id, in_pipe_name,
 // in_from_appletviewer, in_watch_source, out_pipe_name,
 // out_to_appletviewer, out_watch_source, appletviewer_mutex, owner,
 // appletviewer_alive.  In addition two pipe files are created.  All
@@ -284,7 +284,6 @@
   gchar* documentbase = NULL;
   gchar* read_message = NULL;
   gchar* applet_tag = NULL;
-  gchar* tag_message = NULL;
   gchar* cookie_info = NULL;
 
   NPObject* npPluginObj = NULL;
@@ -308,17 +307,17 @@
   // start the jvm if needed
   start_jvm_if_needed();
 
-  // Initialize data->instance_string.
+  // Initialize data->instance_id.
   //
-  // instance_string should be unique for this process so we use a
+  // instance_id should be unique for this process so we use a
   // combination of getpid and plugin_instance_counter.
   //
   // Critical region.  Reference and increment plugin_instance_counter
   // global.
   g_mutex_lock (plugin_instance_mutex);
 
-  // data->instance_string
-  data->instance_string = g_strdup_printf ("%d",
+  // data->instance_id
+  data->instance_id = g_strdup_printf ("%d",
                                            instance_counter);
 
   g_mutex_unlock (plugin_instance_mutex);
@@ -335,11 +334,8 @@
       // Send applet tag message to appletviewer.
       applet_tag = plugin_create_applet_tag (argc, argn, argv);
 
-      tag_message = (gchar*) malloc(strlen(applet_tag)*sizeof(gchar) + strlen(documentbase)*sizeof(gchar) + 32);
-      g_sprintf(tag_message, "instance %d tag %s %s", instance_counter, documentbase, applet_tag);
-
-      //plugin_send_message_to_appletviewer (data, data->instance_string);
-      plugin_send_message_to_appletviewer (tag_message);
+      data->applet_tag = (gchar*) malloc(strlen(applet_tag)*sizeof(gchar) + strlen(documentbase)*sizeof(gchar) + 32);
+      g_sprintf(data->applet_tag, "tag %s %s", documentbase, applet_tag);
 
       data->is_applet_instance = true;
     }
@@ -371,8 +367,12 @@
   data->appletviewer_mutex = NULL;
 
   // cleanup_instance_string:
-  g_free (data->instance_string);
-  data->instance_string = NULL;
+  g_free (data->instance_id);
+  data->instance_id = NULL;
+
+  // cleanup applet tag:
+  g_free (data->applet_tag);
+  data->applet_tag = NULL;
 
   // cleanup_data:
   // Eliminate back-pointer to plugin instance.
@@ -385,8 +385,6 @@
   instance->pdata = NULL;
 
  cleanup_done:
-  g_free (tag_message);
-  tag_message = NULL;
   g_free (applet_tag);
   applet_tag = NULL;
   g_free (read_message);
@@ -750,28 +748,33 @@
     }
   else
     {
+	  // Else this is initialization
       PLUGIN_DEBUG ("ITNP_SetWindow: setting window.\n");
 
       // Critical region.  Send messages to appletviewer.
       g_mutex_lock (data->appletviewer_mutex);
 
-      gchar *window_message = g_strdup_printf ("instance %d handle %ld",
-                                               id, (gulong) window->window);
-      plugin_send_message_to_appletviewer (window_message);
-      g_free (window_message);
-
-      window_message = g_strdup_printf ("instance %d width %d height %d",
-                        id,
-                        window->width,
-                        window->height);
-      plugin_send_message_to_appletviewer (window_message);
-      g_free (window_message);
-      window_message = NULL;
+      // Store the window handle and dimensions
+      data->window_handle = window->window;
+      data->window_width = window->width;
+      data->window_height = window->height;
+
+      // Now we have everything. Send this data to the Java side
+
+      gchar* instance_msg =  g_strdup_printf ("instance %s handle %ld width %d height %d %s",
+											 data->instance_id,
+											 (gulong) data->window_handle,
+											 data->window_width,
+											 data->window_height,
+											 data->applet_tag);
+
+      plugin_send_message_to_appletviewer (instance_msg);
+
+      g_free(instance_msg);
+      instance_msg = NULL;
 
       g_mutex_unlock (data->appletviewer_mutex);
 
-      // Store the window handle.
-      data->window_handle = window->window;
     }
 
   PLUGIN_DEBUG ("ITNP_SetWindow return\n");
@@ -1921,8 +1924,12 @@
   tofree->appletviewer_mutex = NULL;
 
   // cleanup_instance_string:
-  g_free (tofree->instance_string);
-  tofree->instance_string = NULL;
+  g_free (tofree->instance_id);
+  tofree->instance_id = NULL;
+
+  // cleanup applet tag
+  g_free (tofree->applet_tag);
+  tofree->applet_tag = NULL;
 
   g_free(tofree->source);
   tofree->source = NULL;
--- a/plugin/icedteanp/IcedTeaNPPlugin.h	Mon Sep 13 10:21:58 2010 -0400
+++ b/plugin/icedteanp/IcedTeaNPPlugin.h	Thu Sep 16 13:03:57 2010 -0400
@@ -68,7 +68,9 @@
 struct ITNPPluginData
 {
   // A unique identifier for this plugin window.
-  gchar* instance_string;
+  gchar* instance_id;
+  // The applet tag sent to Java side
+  gchar* applet_tag;
   // Mutex to protect appletviewer_alive.
   GMutex* appletviewer_mutex;
   // Back-pointer to the plugin instance to which this data belongs.
--- a/plugin/icedteanp/IcedTeaPluginUtils.cc	Mon Sep 13 10:21:58 2010 -0400
+++ b/plugin/icedteanp/IcedTeaPluginUtils.cc	Thu Sep 16 13:03:57 2010 -0400
@@ -49,7 +49,7 @@
 ************************************************/
 
 // Initialize static variables
-int IcedTeaPluginUtilities::reference = 0;
+int IcedTeaPluginUtilities::reference = -1;
 pthread_mutex_t IcedTeaPluginUtilities::reference_mutex = PTHREAD_MUTEX_INITIALIZER;
 std::map<void*, NPP>* IcedTeaPluginUtilities::instance_map = new std::map<void*, NPP>();
 std::map<std::string, NPObject*>* IcedTeaPluginUtilities::object_map = new std::map<std::string, NPObject*>();
@@ -224,11 +224,11 @@
 	pthread_mutex_lock(&reference_mutex);
 
 	// If we are nearing the max, reset
-	if (reference > 0x7FFFFFFF - 10) {
-	    reference = 0;
+	if (reference < -0x7FFFFFFF + 10) {
+	    reference = -1;
 	}
 
-	reference++;
+	reference--;
 	pthread_mutex_unlock(&reference_mutex);
 
 	return reference;
--- a/plugin/icedteanp/java/sun/applet/PluginAppletViewer.java	Mon Sep 13 10:21:58 2010 -0400
+++ b/plugin/icedteanp/java/sun/applet/PluginAppletViewer.java	Thu Sep 16 13:03:57 2010 -0400
@@ -137,21 +137,10 @@
              }
          });
 
-         double heightFactor = 1.0;
-         double widthFactor = 1.0;
-
-         if (atts.get("heightPercentage") != null) {
-             heightFactor = (Integer) atts.get("heightPercentage")/100.0;
-         }
-         
-         if (atts.get("widthPercentage") != null) {
-             widthFactor = (Integer) atts.get("widthPercentage")/100.0;
-         }
          
 
          // put inside initial 0 handle frame
-         PluginAppletViewer.reFrame(null, identifier, System.out, 
-                 heightFactor, widthFactor, 0, panel);
+         PluginAppletViewer.reFrame(null, identifier, System.out, 0, panel);
          
          panel.init();
 
@@ -362,14 +351,12 @@
      private static HashMap<Integer, PAV_INIT_STATUS> status = 
          new HashMap<Integer,PAV_INIT_STATUS>();
 
-     private double proposedHeightFactor;
-     private double proposedWidthFactor;
      
      private long handle = 0;
      private WindowListener windowEventListener = null;
      private AppletEventListener appletEventListener = null;
      
-     public static final int APPLET_TIMEOUT = 60000;
+     public static final int APPLET_TIMEOUT = 180000;
 
      private static Long requestIdentityCounter = 0L;
      
@@ -381,8 +368,7 @@
 
      public static void reFrame(PluginAppletViewer oldFrame, 
                          int identifier, PrintStream statusMsgStream, 
-                         double heightFactor, double widthFactor, long handle,
-                         AppletViewerPanel panel) {
+                         long handle, AppletViewerPanel panel) {
 
          PluginDebug.debug("Reframing " + panel);
          
@@ -393,7 +379,7 @@
          if (oldFrame != null && handle == oldFrame.handle)
              return;
 
-         PluginAppletViewer newFrame = new PluginAppletViewer(handle, identifier, statusMsgStream, heightFactor, widthFactor, panel);
+         PluginAppletViewer newFrame = new PluginAppletViewer(handle, identifier, statusMsgStream, panel);
 
          if (oldFrame != null) {
              applets.remove(oldFrame.identifier);
@@ -423,14 +409,12 @@
       * Create new plugin appletviewer frame
       */
      private PluginAppletViewer(long handle, final int identifier, 
-                         PrintStream statusMsgStream, double heightFactor, 
-                         double widthFactor, AppletViewerPanel appletPanel) {
+                         PrintStream statusMsgStream, 
+                         AppletViewerPanel appletPanel) {
          
          super(handle, true);
          this.statusMsgStream = statusMsgStream;
          this.identifier = identifier;
-         this.proposedHeightFactor = heightFactor;
-         this.proposedWidthFactor = widthFactor;
          this.panel = appletPanel;
 
          if (!appletPanels.contains(panel))
@@ -525,87 +509,63 @@
          PluginDebug.debug("PAV handling: " + message);
          
          try {
-             if (message.startsWith("tag")) {
+             if (message.startsWith("handle")) {
                  
-                 // tag and handle must both be set before parsing, so we need
-                 // synchronization here, as the setting of these variables
-                 // may happen in independent threads
+            	 // Extract the information from the message
+            	 String[] msgParts = new String[4];
+            	 for (int i=0; i < 3; i++) {
+            		 int spaceLocation = message.indexOf(' ');
+            		 int nextSpaceLocation = message.indexOf(' ', spaceLocation+1);
+            		 msgParts[i] = message.substring(spaceLocation + 1, nextSpaceLocation);
+            		 message = message.substring(nextSpaceLocation + 1);
+            	 }
                  
-                 synchronized(requests) {
+            	 long handle = Long.parseLong(msgParts[0]);
+            	 String width = msgParts[1];
+            	 String height = msgParts[2];
 
-                     // Check if we should proceed with init 
-                     // (=> no if destroy was called after tag, but before 
-                     // handle)
-                     if (status.containsKey(identifier) &&
-                         status.get(identifier).equals(PAV_INIT_STATUS.INACTIVE)) {
+            	 int spaceLocation = message.indexOf(' ', "tag".length()+1); 
+            	 String documentBase = 
+                     UrlUtil.decode(message.substring("tag".length() + 1, spaceLocation));
+            	 String tag = message.substring(spaceLocation+1); 
 
-                         PluginDebug.debug("Inactive flag set. Refusing to initialize instance " + identifier);
-                         requests.remove(identifier);
-                         return;
-
-                     }
+            	 System.err.println("Handle = " + handle + "\n" +
+            	                    "Width = " + width + "\n" +
+            	                    "Height = " + height + "\n" +
+            	                    "DocumentBase = " + documentBase + "\n" +
+            	                    "Tag = " + tag);
 
                      status.put(identifier, PAV_INIT_STATUS.PRE_INIT);
+            	 PluginAppletViewer.parse
+                 			(identifier, handle, width, height,
+                 				new StringReader(tag),
+                 				new URL(documentBase));
                      
-                     PluginParseRequest request = requests.get(identifier);
-                     if (request == null) {
-                         request = new PluginParseRequest();
-                         requests.put(identifier, request);
-                     }
-                     int index = message.indexOf(' ', "tag".length() + 1);
-                     request.documentbase =
-                         UrlUtil.decode(message.substring("tag".length() + 1, index));
-                     request.tag = message.substring(index + 1);
-                     PluginDebug.debug ("REQUEST TAG: " + request.tag + " " +
-                             Thread.currentThread());
+
+                 int maxWait = APPLET_TIMEOUT; // wait for applet to fully load
+                 int wait = 0;
+                 while (!status.get(identifier).equals(PAV_INIT_STATUS.INIT_COMPLETE) &&
+                         (wait < maxWait)) {
 
-                         PluginDebug.debug ("REQUEST TAG, PARSING " +
-                                 Thread.currentThread());
-                         PluginAppletViewer.parse
-                         (identifier, request.handle,
-                                 new StringReader(request.tag),
-                                 new URL(request.documentbase));
-                         requests.remove(identifier);
+                      try {
+                          Thread.sleep(50);
+                          wait += 50;
+                      } catch (InterruptedException ie) {
+                          // just wait
+                      }
+                 }
 
-                         // Panel initialization cannot be aborted mid-way. 
-                         // Once it is initialized, double check to see if this 
-                         // panel needs to stay around..
-                         if (status.get(identifier).equals(PAV_INIT_STATUS.INACTIVE)) {
-                             PluginDebug.debug("Inactive flag set. Destroying applet instance " + identifier);
-                             applets.get(identifier).handleMessage(-1, "destroy");
-                         }
-                 }
+                 if (!status.get(identifier).equals(PAV_INIT_STATUS.INIT_COMPLETE))
+                     throw new Exception("Applet initialization timeout");
+
+                 PluginAppletViewer oldFrame = applets.get(identifier);
+                 reFrame(oldFrame, oldFrame.identifier, oldFrame.statusMsgStream, 
+                         handle, oldFrame.panel);
                  
              } else {
                  PluginDebug.debug ("Handling message: " + message + " instance " + identifier + " " + Thread.currentThread());
 
-                 // Destroy may be called while initialization is still going 
-                 // on. We therefore special case it.
-                 if (!applets.containsKey(identifier) && message.equals("destroy")) {
-
-                     // Set the status to inactive right away. Doesn't matter if it 
-                     // gets clobbered during init. due to a race. That is what the 
-                     // double check below is for.  
-                     PluginDebug.debug("Destroy called during initialization. Delaying destruction.");
-                     status.put(identifier, PAV_INIT_STATUS.INACTIVE);
-
-                     // We have set the flags. We now lock what stage 1 and 2 
-                     // lock on, and force a synchronous status check+action. 
-                     synchronized (requests) {
-                         // re-check (inside lock) if the applet is 
-                         // initialized at this point. 
-                         if (applets.containsKey(identifier)) {
-                             PluginDebug.debug("Init done. destroying normally.");
-                             applets.get(identifier).handleMessage(reference, message);
-                         } else {
-                         }
-                     } // unlock
-
-                     // we're done here
-                     return;
-                 }
-
-                 // For messages other than destroy, wait till initialization finishes
+                 // Wait till initialization finishes
                  while (!applets.containsKey(identifier) && 
                          (
                            !status.containsKey(identifier) || 
@@ -617,37 +577,7 @@
                  if (status.get(identifier).equals(PAV_INIT_STATUS.INACTIVE))
                      return;
 
-                 if (message.startsWith("handle")) {
-
-                     PluginDebug.debug("handle command waiting for applet to complete loading.");
-                     int maxWait = APPLET_TIMEOUT; // wait for applet to fully load
-                     int wait = 0;
-                     while (!status.get(identifier).equals(PAV_INIT_STATUS.INIT_COMPLETE) &&
-                             (wait < maxWait)) {
-
-                          try {
-                              Thread.sleep(50);
-                              wait += 50;
-                          } catch (InterruptedException ie) {
-                              // just wait
-                          }
-                     }
-
-                     if (!status.get(identifier).equals(PAV_INIT_STATUS.INIT_COMPLETE))
-                         throw new Exception("Applet initialization timeout");
-
-                     PluginDebug.debug("Applet loading complete. Proceeding to reframe.");
-                     long handle = Long.parseLong
-                     (message.substring("handle".length() + 1));
-
-                     PluginAppletViewer oldFrame = applets.get(identifier);
-                     reFrame(oldFrame, oldFrame.identifier, oldFrame.statusMsgStream, 
-                             oldFrame.proposedHeightFactor, oldFrame.proposedWidthFactor, 
-                             handle, oldFrame.panel);
-                     
-                 } else {
-                     applets.get(identifier).handleMessage(reference, message);
-                 }
+                 applets.get(identifier).handleMessage(reference, message);
              }
          } catch (Exception e) {
 
@@ -668,21 +598,23 @@
 
              // Wait for panel to come alive
              int maxWait = APPLET_TIMEOUT; // wait for panel to come alive
-             int wait = 0;
+                     int wait = 0;
              while (!status.get(identifier).equals(PAV_INIT_STATUS.INIT_COMPLETE) && wait < maxWait) {
-                  try {
-                      Thread.sleep(50);
-                      wait += 50;
-                  } catch (InterruptedException ie) {
-                      // just wait
-                  }
-             }
+
+                          try {
+                              Thread.sleep(50);
+                              wait += 50;
+                          } catch (InterruptedException ie) {
+                              // just wait
+                          }
+                     }
+
              
              // 0 => width, 1=> width_value, 2 => height, 3=> height_value
              String[] dimMsg = message.split(" ");
              
-             final int height = (int) (proposedHeightFactor*Integer.parseInt(dimMsg[3]));
-             final int width = (int) (proposedWidthFactor*Integer.parseInt(dimMsg[1]));
+             final int height = (int) (Integer.parseInt(dimMsg[3]));
+             final int width = (int) (Integer.parseInt(dimMsg[1]));
 
              if (panel instanceof NetxPanel)
                  ((NetxPanel) panel).updateSizeInAtts(height, width);
@@ -708,6 +640,9 @@
 
                          panel.setSize(width, height);
                          panel.validate();
+
+                         panel.applet.resize(width, height);
+                         panel.applet.validate();
                      }
                  });
             } catch (InterruptedException e) {
@@ -1642,60 +1577,55 @@
  
  
      /**
-      * The current character.
-      */
-     static int c;
- 
-     /**
       * Scan spaces.
       */
-     public static void skipSpace(Reader in) throws IOException {
-         while ((c >= 0) &&
-           ((c == ' ') || (c == '\t') || (c == '\n') || (c == '\r'))) {
-        c = in.read();
+     public static void skipSpace(int[] c, Reader in) throws IOException {
+         while ((c[0] >= 0) &&
+           ((c[0] == ' ') || (c[0] == '\t') || (c[0] == '\n') || (c[0] == '\r'))) {
+        	 c[0] = in.read();
     }
      }
  
      /**
       * Scan identifier
       */
-     public static String scanIdentifier(Reader in) throws IOException {
+     public static String scanIdentifier(int[] c, Reader in) throws IOException {
     StringBuffer buf = new StringBuffer();
     
-    if (c == '!') {
+    if (c[0] == '!') {
         // Technically, we should be scanning for '!--' but we are reading 
         // from a stream, and there is no way to peek ahead. That said, 
         // a ! at this point can only mean comment here afaik, so we 
         // should be okay
-        skipComment(in);
+        skipComment(c, in);
         return "";
     }
     
     while (true) {
-        if (((c >= 'a') && (c <= 'z')) ||
-        ((c >= 'A') && (c <= 'Z')) ||
-        ((c >= '0') && (c <= '9')) || (c == '_')) {
-        buf.append((char)c);
-        c = in.read();
+        if (((c[0] >= 'a') && (c[0] <= 'z')) ||
+        ((c[0] >= 'A') && (c[0] <= 'Z')) ||
+        ((c[0] >= '0') && (c[0] <= '9')) || (c[0] == '_')) {
+        buf.append((char)c[0]);
+        c[0] = in.read();
         } else {
         return buf.toString();
         }
     }
      }
 
-     public static void skipComment(Reader in) throws IOException {
+     public static void skipComment(int[] c, Reader in) throws IOException {
          StringBuffer buf = new StringBuffer();
          boolean commentHeaderPassed = false;
-         c = in.read();
-         buf.append((char)c);
+         c[0] = in.read();
+         buf.append((char)c[0]);
 
          while (true) {
-             if (c == '-' && (c = in.read()) == '-') {
-                 buf.append((char)c);
+             if (c[0] == '-' && (c[0] = in.read()) == '-') {
+                 buf.append((char)c[0]);
                  if (commentHeaderPassed) {
                      // -- encountered ... is > next?
-                     if ((c = in.read()) == '>') {
-                         buf.append((char)c);
+                     if ((c[0] = in.read()) == '>') {
+                         buf.append((char)c[0]);
 
                          PluginDebug.debug("Comment skipped: " + buf.toString());
 
@@ -1708,46 +1638,46 @@
                  }
 
              } else if (commentHeaderPassed == false) {
-                 buf.append((char)c);
+                 buf.append((char)c[0]);
                  PluginDebug.debug("Warning: Attempted to skip comment, but this tag does not appear to be a comment: " + buf.toString());
                  return;
              }
 
-             c = in.read();
-             buf.append((char)c);
+             c[0] = in.read();
+             buf.append((char)c[0]);
          }
      }
  
      /**
       * Scan tag
       */
-     public static Hashtable scanTag(Reader in) throws IOException {
+     public static Hashtable scanTag(int[] c, Reader in) throws IOException {
     Hashtable atts = new Hashtable();
-    skipSpace(in);
-         while (c >= 0 && c != '>') {
-        String att = scanIdentifier(in);
+    skipSpace(c, in);
+         while (c[0] >= 0 && c[0] != '>') {
+        String att = scanIdentifier(c, in);
         String val = "";
-        skipSpace(in);
-        if (c == '=') {
+        skipSpace(c, in);
+        if (c[0] == '=') {
         int quote = -1;
-        c = in.read();
-        skipSpace(in);
-        if ((c == '\'') || (c == '\"')) {
-            quote = c;
-            c = in.read();
+        c[0] = in.read();
+        skipSpace(c, in);
+        if ((c[0] == '\'') || (c[0] == '\"')) {
+            quote = c[0];
+            c[0] = in.read();
         }
         StringBuffer buf = new StringBuffer();
-                 while ((c > 0) &&
-               (((quote < 0) && (c != ' ') && (c != '\t') &&
-                          (c != '\n') && (c != '\r') && (c != '>'))
-            || ((quote >= 0) && (c != quote)))) {
-            buf.append((char)c);
-            c = in.read();
+                 while ((c[0] > 0) &&
+               (((quote < 0) && (c[0] != ' ') && (c[0] != '\t') &&
+                          (c[0] != '\n') && (c[0] != '\r') && (c[0] != '>'))
+            || ((quote >= 0) && (c[0] != quote)))) {
+            buf.append((char)c[0]);
+            c[0] = in.read();
         }
-        if (c == quote) {
-            c = in.read();
+        if (c[0] == quote) {
+            c[0] = in.read();
         }
-        skipSpace(in);
+        skipSpace(c, in);
         val = buf.toString();
         }
 
@@ -1767,12 +1697,12 @@
         atts.put(att.toLowerCase(java.util.Locale.ENGLISH), val);
 
              while (true) {
-                 if ((c == '>') || (c < 0) ||
-                     ((c >= 'a') && (c <= 'z')) ||
-                     ((c >= 'A') && (c <= 'Z')) ||
-                     ((c >= '0') && (c <= '9')) || (c == '_'))
+                 if ((c[0] == '>') || (c[0] < 0) ||
+                     ((c[0] >= 'a') && (c[0] <= 'z')) ||
+                     ((c[0] >= 'A') && (c[0] <= 'Z')) ||
+                     ((c[0] >= '0') && (c[0] <= '9')) || (c[0] == '_'))
                      break;
-                 c = in.read();
+                 c[0] = in.read();
              }
              //skipSpace(in);
     }
@@ -1815,23 +1745,25 @@
      /**
       * Scan an html file for <applet> tags
       */
-     public static void parse(int identifier, long handle, Reader in, URL url, String enc)
+     public static void parse(int identifier, long handle, String width, String height, Reader in, URL url, String enc)
          throws IOException {
          encoding = enc;
-         parse(identifier, handle, in, url, System.out, new PluginAppletPanelFactory());
+         parse(identifier, handle, width, height, in, url, System.out, new PluginAppletPanelFactory());
      }
  
-     public static void parse(int identifier, long handle, Reader in, URL url)
+     public static void parse(int identifier, long handle, String width, String height, Reader in, URL url)
          throws IOException {
          
          final int fIdentifier = identifier;
          final long fHandle = handle;
+         final String fWidth = width;
+         final String fHeight = height;
          final Reader fIn = in;
          final URL fUrl = url;
          PrivilegedAction pa = new PrivilegedAction() {
              public Object run() {
                  try {
-                     parse(fIdentifier, fHandle, fIn, fUrl, System.out, new PluginAppletPanelFactory());
+                     parse(fIdentifier, fHandle, fWidth, fHeight, fIn, fUrl, System.out, new PluginAppletPanelFactory());
                  } catch (IOException ioe) {
                      return ioe;
                  }
@@ -1846,7 +1778,8 @@
          }
      }
  
-     public static void parse(int identifier, long handle, Reader in, URL url,
+     public static void parse(int identifier, long handle, String width, 
+    		 String height, Reader in, URL url,
                               PrintStream statusMsgStream,
                               PluginAppletPanelFactory factory)
          throws IOException
@@ -1856,6 +1789,11 @@
          boolean isObjectTag = false;
          boolean isEmbedTag = false;
          boolean objectTagAlreadyParsed = false;
+         // The current character
+         // FIXME: This is an evil hack to force pass-by-reference.. the 
+         // parsing code needs to be rewritten from scratch to prevent such 
+         //a need
+         int[] c = new int[1];
 
          // warning messages
          String requiresNameWarning = amh.getMessage("parse.warning.requiresname");
@@ -1881,15 +1819,15 @@
          Hashtable atts = null;
 
          while(true) {
-             c = in.read();
-             if (c == -1)
+             c[0] = in.read();
+             if (c[0] == -1)
                  break;
 
-             if (c == '<') {
-                 c = in.read();
-                 if (c == '/') {
-                     c = in.read();
-                     String nm = scanIdentifier(in);
+             if (c[0] == '<') {
+                 c[0] = in.read();
+                 if (c[0] == '/') {
+                     c[0] = in.read();
+                     String nm = scanIdentifier(c, in);
                      if (nm.equalsIgnoreCase("applet") ||
                              nm.equalsIgnoreCase("object") ||
                              nm.equalsIgnoreCase("embed")) {
@@ -1930,9 +1868,9 @@
                      }
                  }
                  else {
-                     String nm = scanIdentifier(in);
+                     String nm = scanIdentifier(c, in);
                      if (nm.equalsIgnoreCase("param")) {
-                         Hashtable t = scanTag(in);
+                         Hashtable t = scanTag(c, in);
                          String att = (String)t.get("name");
 
                          if (atts.containsKey(att))
@@ -1967,7 +1905,7 @@
                      }
                      else if (nm.equalsIgnoreCase("applet")) {
                          isAppletTag = true;
-                         atts = scanTag(in);
+                         atts = scanTag(c, in);
 
                          // If there is a classid and no code tag present, transform it to code tag
                          if (atts.get("code") == null && atts.get("classid") != null && !((String) atts.get("classid")).startsWith("clsid:")) {
@@ -1985,21 +1923,11 @@
                          }
 
                          if (atts.get("width") == null || !isInt(atts.get("width"))) {
-                             atts.put("width", "1000");
-                             atts.put("widthPercentage", 100);
-                         } else if (((String) atts.get("width")).endsWith("%")) {
-                             String w = (String) atts.get("width");
-                             atts.put("width", "100");
-                             atts.put("widthPercentage", Integer.parseInt((w.substring(0,  w.length() -1))));
+                             atts.put("width", width);
                           }
 
                          if (atts.get("height") == null || !isInt(atts.get("height"))) {
-                             atts.put("height", "1000");
-                             atts.put("heightPercentage", 100);
-                         } else if (((String) atts.get("height")).endsWith("%")) {
-                             String h = (String) atts.get("height");
-                             atts.put("height", "100");
-                             atts.put("heightPercentage", Integer.parseInt(h.substring(0,  h.length() -1)));
+                             atts.put("height", height);
                          }
                      }
                      else if (nm.equalsIgnoreCase("object")) {
@@ -2008,7 +1936,7 @@
                          // Once code is set, additional nested objects are ignored
                          if (!objectTagAlreadyParsed) {
                              objectTagAlreadyParsed = true;
-                         atts = scanTag(in);
+                         atts = scanTag(c, in);
                          }
 
                          // If there is a classid and no code tag present, transform it to code tag
@@ -2048,26 +1976,16 @@
                          }
 
                          if (atts.get("width") == null || !isInt(atts.get("width"))) {
-                             atts.put("width", "1000");
-                             atts.put("widthPercentage", 100);
-                         } else if (((String) atts.get("width")).endsWith("%")) {
-                             String w = (String) atts.get("width");
-                             atts.put("width", "100");
-                             atts.put("widthPercentage", Integer.parseInt(w.substring(0,  w.length() -1)));
+                             atts.put("width", width);
                          }
 
                          if (atts.get("height") == null || !isInt(atts.get("height"))) {
-                             atts.put("height", "1000");
-                             atts.put("heightPercentage", 100);
-                         } else if (((String) atts.get("height")).endsWith("%")) {
-                             String h = (String) atts.get("height");
-                             atts.put("height", "100");
-                             atts.put("heightPercentage", Integer.parseInt(h.substring(0,  h.length() -1)));
+                             atts.put("height", height);
                          }
                      }
                      else if (nm.equalsIgnoreCase("embed")) {
                          isEmbedTag = true;
-                         atts = scanTag(in);
+                         atts = scanTag(c, in);
 
                          // If there is a classid and no code tag present, transform it to code tag
                          if (atts.get("code") == null && atts.get("classid") != null && !((String) atts.get("classid")).startsWith("clsid:")) {
@@ -2107,21 +2025,11 @@
                          }
                          
                          if (atts.get("width") == null || !isInt(atts.get("width"))) {
-                             atts.put("width", "1000");
-                             atts.put("widthPercentage", 100);
-                         } else if (((String) atts.get("width")).endsWith("%")) {
-                             String w = (String) atts.get("width");
-                             atts.put("width", "100");
-                             atts.put("widthPercentage", Integer.parseInt(w.substring(0,  w.length() -1)));
+                             atts.put("width", width);
                          }
 
                          if (atts.get("height") == null || !isInt(atts.get("height"))) {
-                             atts.put("height", "1000");
-                             atts.put("heightPercentage", 100);
-                         } else if (((String) atts.get("height")).endsWith("%")) {
-                             String h = (String) atts.get("height");
-                             atts.put("height", "100");
-                             atts.put("heightPercentage", Integer.parseInt(h.substring(0,  h.length() -1)));
+                             atts.put("height", height);
                          }
                      }
                  }
--- a/plugin/icedteanp/java/sun/applet/PluginMessageConsumer.java	Mon Sep 13 10:21:58 2010 -0400
+++ b/plugin/icedteanp/java/sun/applet/PluginMessageConsumer.java	Thu Sep 16 13:03:57 2010 -0400
@@ -50,7 +50,7 @@
 	// Each initialization requires 5 responses (tag, handle, width, proxy, cookie) 
 	// before the message stack unlocks/collapses. This works out well because we 
 	// want to allow upto 5 parallel tasks anyway
-	private static int MAX_WORKERS = MAX_PARALLEL_INITS*5;
+	private static int MAX_WORKERS = MAX_PARALLEL_INITS*4;
 	private static int PRIORITY_WORKERS = MAX_PARALLEL_INITS*2;
 
 	private static Hashtable<Integer, PluginMessageHandlerWorker> initWorkers = new Hashtable<Integer, PluginMessageHandlerWorker>(2);
@@ -150,41 +150,6 @@
         }
 	}
 
-	private boolean okayToProcess(String[] msgParts) {
-
-	    if (msgParts[2].equals("tag")) {
-
-	        Integer instanceNum = new Integer(msgParts[1]);
-
-	        synchronized(initWorkers) {
-	            if (initWorkers.size() >= MAX_PARALLEL_INITS) {
-	                return false;
-	            }
-	        }
-	        
-	        registerPriorityWait("instance " + instanceNum + " handle");
-
-	    } else if (msgParts[2].equals("handle")) {
-	            Integer instanceNum = new Integer(msgParts[1]);
-
-	            // If this instance is not in init, return false immediately. 
-	            // Handle messages should NEVER go before tag messages
-	            if (!isInInit(instanceNum))
-	                return false;
-
-		        registerPriorityWait("instance " + instanceNum + " width");
-	    } else if (msgParts[2].equals("width")) {
-	    	
-	    	// width messages cannot proceed until handle and tag have been resolved
-	    	Integer instanceNum = new Integer(msgParts[1]);
-
-	    	if (!processedIds.contains(instanceNum)) {
-                return false;
-            }
-	    }
-
-	    return true;
-	}
 
 	public void notifyWorkerIsFree(PluginMessageHandlerWorker worker) {
 	    synchronized (initWorkers) {
@@ -225,14 +190,6 @@
 
 	                String[] msgParts = message.split(" ");
 
-	                // if it is no okay to process just yet, push it back and 
-	                if (!okayToProcess(msgParts)) {
-	                    synchronized(readQueue) {
-	                        readQueue.addLast(message);
-	                    }
-	                    
-	                    continue; // re-loop to try next msg
-	                }
 
 	                String priorityStr = getPriorityStrIfPriority(message);
 	                boolean isPriorityResponse = (priorityStr != null);