Latest testing of LSNG with NVDA has revealed that there's still an edge case which leads to a deadlock. I created an experimental patch and according to QA it fixes occasional hangs.
Here's the problem. When localStorage for a content process is accessed for the first time, we need to create the DOM File thread if it doesn't exist and also initialize PBackground on that thread. BackgroundChild::GetOrCreateForCurrentThread is synchronous and happens mostly on the current thread (DOM File thread in this cas). However, last step consists of creating a runnable that must run on the main thread because it needs to send an async message to the parent via PContent, to finish PBackground initialization for the thread. At the same time we block the main thread, so the runnable wouldn't have a chance to run, but we fixed that by passing a nested event queue/target to BackgroundChild::GetOrCreateForCurrentThread.
Anyway, it can happen, that at the same time, the main process is issuing a synchronous call to the content process on the main thread, so the async IPC message that was sent from content to finish PBackground initialization can't be handled because of the sync call. As I mentioned, we block the main thread in the content process, so this all leads to a deadlock.
I think we can mitigate this by creating DOM File thread and PBackground child in advance.