head	1.2;
access;
symbols;
locks; strict;
comment	@# @;


1.2
date	2011.04.26.18.56.14;	author jkim;	state dead;
branches;
next	1.1;

1.1
date	2011.03.29.16.46.53;	author jkim;	state Exp;
branches;
next	;


desc
@@


1.2
log
@- Update to 1.3.2 and remove obsolete local patches.
- Replace the defunct URL with a new upstream location.  Now this project has
a new maintainer:

https://www.redhat.com/archives/nspluginwrapper-devel-list/2011-April/msg00003.html

For more information about this release, please see the following thread:

https://www.redhat.com/archives/nspluginwrapper-devel-list/2011-April/msg00006.html

Prodded by:	Benjamin Kaduk (kaduk at MIT dot EDU), arundel
@
text
@--- src/npw-viewer.c.orig	2011-03-28 17:46:24.000000000 -0400
+++ src/npw-viewer.c	2011-03-28 17:52:16.000000000 -0400
@@@@ -221,8 +221,17 @@@@
 static GList *g_delayed_calls = NULL;
 static guint g_delayed_calls_id = 0;
 
+// We put delayed NPP_Destroy calls on a separate list because, unlike
+// NPN_ReleaseObject, these must be called on a clean stack and have no
+// other cause to get cleared. Otherwise, it is possible for the
+// delayed_calls_process in g_NPP_Destroy_Now to call it early.
+static GList *g_delayed_destroys = NULL;
+static guint g_delayed_destroys_id = 0;
+
 static void g_NPN_ReleaseObject_Now(NPObject *npobj);
+static NPError g_NPP_Destroy_Now(PluginInstance *plugin, NPSavedData **sdata);
 static gboolean delayed_calls_process_cb(gpointer user_data);
+static gboolean delayed_destroys_process_cb(gpointer user_data);
 
 static void delayed_calls_add(int type, gpointer data)
 {
@@@@ -238,13 +247,19 @@@@
 										 delayed_calls_process_cb, NULL, NULL);
 }
 
+static void delayed_destroys_add(PluginInstance *plugin)
+{
+  g_delayed_destroys = g_list_append(g_delayed_destroys, plugin);
+
+  if (g_delayed_destroys_id == 0)
+	g_delayed_destroys_id = g_idle_add_full(G_PRIORITY_LOW,
+											delayed_destroys_process_cb, NULL, NULL);
+}
+
 // Returns whether there are pending calls left in the queue
 static gboolean delayed_calls_process(PluginInstance *plugin, gboolean is_in_NPP_Destroy)
 {
-  GList *l = g_delayed_calls;
-  while (l != NULL) {
-	GList *cl = l;
-	l = l->next;
+  while (g_delayed_calls != NULL) {
 
 	if (!is_in_NPP_Destroy) {
 	  /* Continue later if there is incoming RPC */
@@@@ -252,7 +267,11 @@@@
 		return TRUE;
 	}
 
-	DelayedCall *dcall = (DelayedCall *)cl->data;
+	DelayedCall *dcall = (DelayedCall *)g_delayed_calls->data;
+	/* XXX: Remove the link first; this function /must/ be
+	 * re-entrant. We may be called again while processing the
+	 * delayed call. */
+	g_delayed_calls = g_list_delete_link(g_delayed_calls, g_delayed_calls);
 	switch (dcall->type) {
 	case RPC_DELAYED_NPN_RELEASE_OBJECT:
 	  {
@@@@ -262,7 +281,6 @@@@
 	  }
 	}
 	NPW_MemFree(dcall);
-	g_delayed_calls = g_list_delete_link(g_delayed_calls, cl);
   }
 
   if (g_delayed_calls)
@@@@ -280,6 +298,25 @@@@
   return delayed_calls_process(NULL, FALSE);
 }
 
+static gboolean delayed_destroys_process_cb(gpointer user_data)
+{
+  while (g_delayed_destroys != NULL) {
+	PluginInstance *plugin = (PluginInstance *)g_delayed_destroys->data;
+	g_delayed_destroys = g_list_delete_link(g_delayed_destroys,
+											g_delayed_destroys);
+	g_NPP_Destroy_Now(plugin, NULL);
+  }
+
+  if (g_delayed_destroys)
+	return TRUE;
+
+  if (g_delayed_destroys_id) {
+	g_source_remove(g_delayed_destroys_id);
+	g_delayed_destroys_id = 0;
+  }
+  return FALSE;
+}
+
 // NPIdentifier cache
 static inline bool use_npidentifier_cache(void)
 {
@@@@ -741,7 +778,6 @@@@
   }
 }
 
-
 /* ====================================================================== */
 /* === XPCOM glue                                                     === */
 /* ====================================================================== */
@@@@ -3338,6 +3374,13 @@@@
 	return error;
   }
 
+  /* Clear any NPP_Destroys we may have delayed. Although it doesn't
+     really matter, and the plugin is going to die soon.
+
+	 XXX: To be really picky, we should probably delay this and make
+	 sure it is run on a new event loop iteration. */
+  delayed_destroys_process_cb(NULL);
+
   NPError ret = g_NP_Shutdown();
   return rpc_method_send_reply(connection, RPC_TYPE_INT32, ret, RPC_TYPE_INVALID);
 }
@@@@ -3459,6 +3502,8 @@@@
 
   // Process all pending calls as the data could become junk afterwards
   // XXX: this also processes delayed calls from other instances
+  // XXX: Also, if this was delayed, the NPN_ReleaseObject calls will
+  // be ignored; the browser thinks we've already died.
   delayed_calls_process(plugin, TRUE);
 
   D(bugiI("NPP_Destroy instance=%p\n", instance));
@@@@ -3473,6 +3518,22 @@@@
   return ret;
 }
 
+static NPError g_NPP_Destroy_Now(PluginInstance *plugin, NPSavedData **save)
+{
+  D(bug("g_NPP_Destroy_Now\n"));
+
+  NPSavedData *save_area = NULL;
+  NPError ret = g_NPP_Destroy(PLUGIN_INSTANCE_NPP(plugin), &save_area);
+  if (save) {
+	*save = save_area;
+  } else if (save_area) {
+	npw_printf("WARNING: NPP_Destroy returned save_area, but it was ignored\n");
+  }
+
+  rpc_connection_unref(g_rpc_connection);
+  return ret;
+}
+
 static int handle_NPP_Destroy(rpc_connection_t *connection)
 {
   D(bug("handle_NPP_Destroy\n"));
@@@@ -3488,8 +3549,26 @@@@
 	return error;
   }
 
-  NPSavedData *save_area;
-  NPError ret = g_NPP_Destroy(PLUGIN_INSTANCE_NPP(plugin), &save_area);
+  NPSavedData *save_area = NULL;
+  NPError ret = NPERR_NO_ERROR;
+  /* Take a ref for the rpc_method_send_reply; otherwise the
+   * rpc_connection_unref in g_NPP_Destroy_Now may cause a slight
+   * nuisance. */
+  rpc_connection_ref(connection);
+  if (!rpc_method_in_invoke(connection)) {
+	/* The plugin is not on the stack; it's safe to call this. */
+	D(bug("NPP_Destroy is fine.\n"));
+	ret = g_NPP_Destroy_Now(plugin, &save_area);
+  } else {
+	/* It is not safe to call NPP_Destroy right now. Delay it until we
+	 * return to the event loop.
+	 *
+	 * NOTE: This means that the browser never sees the real return
+	 * value of NPP_Destroy; the NPSavedData will be discarded, and any
+	 * error code will be ignored. */
+    D(bug("NPP_Destroy raced; delaying it to get a clean stack.\n"));
+	delayed_destroys_add(plugin);
+  }
 
   error = rpc_method_send_reply(connection,
 								RPC_TYPE_INT32, ret,
--- src/rpc.c.orig	2009-01-02 09:22:29.000000000 -0500
+++ src/rpc.c	2011-03-28 17:52:16.000000000 -0400
@@@@ -2097,6 +2097,22 @@@@
   return ret;
 }
 
+bool rpc_method_in_invoke(rpc_connection_t *connection)
+{
+  D(bug("rpc_method_in_invoke\n"));
+  if (connection == NULL)
+	return false;
+  // Our stack should alternate between handle/dispatch and
+  // invokes. Some calls are only safe to handle called from an event
+  // loop. In this case, we should have values invoke_depth = 0;
+  // handle_depth = 1; dispatch_depth = 1
+  D(bug("invoke_depth = %d; dispatch_depth = %d; handle_depth = %d\n",
+		connection->invoke_depth,
+		connection->dispatch_depth,
+		connection->handle_depth));
+  return connection->invoke_depth > 0;
+}
+
 
 /* ====================================================================== */
 /* === Test Program                                                   === */
--- src/rpc.h.orig	2009-01-02 09:22:29.000000000 -0500
+++ src/rpc.h	2011-03-28 17:52:16.000000000 -0400
@@@@ -119,6 +119,7 @@@@
 extern int rpc_method_wait_for_reply(rpc_connection_t *connection, ...) attribute_hidden;
 extern int rpc_method_get_args(rpc_connection_t *connection, ...) attribute_hidden;
 extern int rpc_method_send_reply(rpc_connection_t *connection, ...) attribute_hidden;
+extern bool rpc_method_in_invoke(rpc_connection_t *connection) attribute_hidden;
 
 #ifdef __cplusplus
 }
@


1.1
log
@Fix a race condition on NPP_Destroy.  With this patch, Adobe Flash plugin
is quite bearable now.  For more detailed info, please see the Red Hat PR:

https://bugzilla.redhat.com/show_bug.cgi?id=680279

Obtained from:	Fedora Project
@
text
@@

