Proposal for serializing NPAPI across processes

Chris Jones <[email protected]>
Newsgroups gmane.comp.mozilla.devel.dom
Message-ID <[email protected]>
Putting plugins in a separate process breaks the current NPAPI threading 
model.  The reason is that a plugin can register callbacks into a native 
event loop in its subprocess.  This allows a plugin's callback to run 
concurrently with browser code, because we have no (apparent) way of 
controlling the delivery of native events to the plugin process on all 
our platforms.  (We do for X.)  This breaks the single-threaded NPAPI 
model by allowing plugin code to call into the browser concurrently with 
the browser calling into the plugin.  Unfortunately this can arise for 
both windowed and windowless plugins, because apparently in the wild, 
windowless plugins create native child windows.  This proposal intends 
to fix this problem, and preserve the "single thread of control" model 
of NPAPI.

(Aside: the proposal here
https://wiki.mozilla.org/Plugins:PlatformIndependentNPAPI
intends to achieve something similar to what is described in this 
message, but as its name says, by eliminating native event handling. 
This proposal instead intends to make similar guarantees within the 
existing NPAPI, allowing native event handling.)

The only way plugin code can acquire an execution context without the 
browser's supervision is through a native event callback in its 
subprocess.  So, the dirt simple solution is to get plugin vendors to 
modify the way they handle native events; it's as simple as, upon 
receiving a native event, call NPN_PluginThreadAsyncCall() to register a 
callback with the browser.  This should hopefully be a small 
modification to existing plugin code.  Josh has offered to discuss this 
modification with plugin vendors; hopefully we can soon get a timetable 
for this modification.

(It's not strictly necessary for plugins to do this for /all/ native 
events, only for those whose callbacks might invoke an NPN_ function. 
But that's an optimization.)

This small change allows us to "forward" plugin events to the main 
browser event loop.  The implementation would be approximately as 
follows.  Our Gecko code in the plugin process would implement 
NPN_PluginThreadAsyncCall().  When the plugin invokes this function, our 
code will send an *asynchronous* PluginWantsCallback() message to the 
browser process.  A handler will then be enqueued into the browser's 
event queue.  When it's dequeued, the handler will send an RPC 
CallPluginCallback() message to the plugin process, and our code in the 
plugin process will call the plugin's callback, which is then free to do 
whatever it wants.  This has the advantage of serializing *all* NPAPI 
messages across all plugins approximately the same way they would be in 
the current single-process, single-event loop implementation.  It also 
happens to neatly fit into our current event and IPDL frameworks.  (And 
we need to implement NPN_PluginThreadAsyncCall() regardless of resolving 
race conditions arising from native events.)

The big question is, what if plugin vendors refuse this change?  If this 
happens, I don't think it's possible for us to serialize script 
invocations; plugin runtimes will always be able to race with our JS 
runtime, and one runtime will "lose" by not getting run-to-completion 
semantics.  One solution to this problem is to detect these races and 
kill the plugin process if they occur.  Another is to cross our fingers 
and pray the races doesn't cause problems.  If we ignore scripts, I 
believe that we might be able to serialize the remaining NPP/NPN 
functions, including NPStream messages, as described in the previous 
thread.  That would require some pain, though,

Cheers,
Chris
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.