My first significant project at Mozilla has been bug 805591, implementing a user interface to be displayed by Firefox when an out-of-process plugin hangs. This is important because when NPAPI plugins hang, they block the main thread in Firefox. When the main thread is blocked, the Firefox user interface grinds to a halt.
The purpose of the Plugin Hang UI is twofold:
- To inform the user which plugin is responsible for the hang; and
- Provide the user with an opportunity to terminate the plugin if he/she wishes.
Currently this is feature is exclusive to Firefox Desktop on Windows. When the Hang UI is invoked, you’ll notice that Firefox has created a new child process, plugin-hang-ui.exe. This child process will display the Plugin Hang UI dialog box.
My patch is currently under review, but the Plugin Hang UI is fully functional in a try build, so please check it out and play with it!
Changes to Preferences
dom.ipc.plugins.hangUITimeoutSecs: This is the number of seconds that Firefox waits for a hung plugin before displaying the Plugin Hang UI. Setting this value to zero disables the Plugin Hang UI.
dom.ipc.plugins.timeoutSecs: This pref is still used with the Hang UI, but its semantics change a little bit. Once the Plugin Hang UI has been displayed, Firefox will wait
dom.ipc.plugins.timeoutSecsseconds before terminating the plugin automatically, even if the user did not elect to stop the plugin using the Hang UI. This is nearly identical to the way that Firefox behaves without the Hang UI — the only difference is that now this timeout period doesn’t commence until the Hang UI is displayed.
dom.ipc.plugins.hangUIMinDisplaySecs: This is the minimum number of seconds that Firefox should display the Plugin Hang UI. If
dom.ipc.plugins.timeoutSecsis set to a value lower than this pref, the Hang UI is disabled. The idea here is that, if
dom.ipc.plugins.timeoutSecsis only set to 5 seconds to begin with, then the plugin will already have been auto terminated before the user has half a chance to read the Plugin Hang UI.
There are a couple of interesting things that I’d like to point out relating to this patch.
Because the Plugin Hang UI is a child process, I needed to ensure that
its window always appears in front of the hung Firefox window. I decided
that I would have Firefox send its top-level
HWND over to the child
process so that the Hang UI could specify that handle as the owner of its
top-level window. If you’ve seen Raymond Chen’s
Five Things Every Win32 Programmer Needs to Know,
then you’ll know what is coming: Deadlock!
The problem is that the Hang UI window and the Firefox window are created by different threads. When I set the owner relationship between the Hang UI top-level window and the Firefox top-level window, the window manager implicitly synchronizes both threads’ input queues. In the case of the Plugin Hang UI, this is a huge problem: Windows just synchronized the Hang UI’s input queue with a hung thread!
What’s the solution, then? Think about it this way: the window manager might have implicitly synchronized the two threads’ input queues, but there’s no reason why we can’t then explicitly desynchronize them!
Here’s the first thing I do in the Plugin Hang UI’s
1 2 3 4
Without this line, the Hang UI is at risk of deadlock. This is especially true if the user attempts to send input to the Firefox window underneath.