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