Bug 1553982 Comment 26 Edit History

Note: The actual edited comment in the bug view page will always show the original commenter’s name and original timestamp.

I have spent a fair amount of time looking into this on multiple occasions because I can never seem to remember exactly how it works or why it does what it does. This question prompted me to do this again today. :nalexander beat me to actually answering the question, but I want to leave a record of what this does and why, mostly to make it easier on myself the next time I need to look into this.

Firefox has two related things going on with regard to checking for other instances. The [update mutex](https://searchfox.org/mozilla-central/rev/ea1234192518e01694a88eac8ff090e4cadf5ca4/toolkit/mozapps/update/UpdateService.jsm#627) and `nsIUpdateSyncManager`.

The update mutex:
- Has existed for a long time.
- Works similarly to a normal mutex, but is automatically closed if Firefox crashes.
- Is locked when an installation of Firefox tries to update.
- If it cannot be acquired, it means that another instance of Firefox is handling update, so the update system pretty much lets the other instance handle it.

Whereas `nsIUpdateSyncManager`:
- Was created more recently (in this bug).
- Is implemented via a read/write lock system. Each Firefox instance takes a read lock. The write lock can only be taken if there are no other instances with read locks. (Note that I only checked the Windows implementation when I wrote this. I seem to recall that we do slightly different things on other OS's, but I believe they work in similar ways)
- A read lock is taken when Firefox starts. This allows `nsIUpdateSyncManager` to be able to say pretty definitively if any other instances are running, not just if any are updating.
- `nsIUpdateSyncManager` reporting another instance running has a couple of effects.
    - It causes the update interfaces to indicate that update is being handled by another instance. This message isn't quite correct, but the intention is basically correct since if you have multiple instances open, it's not the best time to update.
    - If/when we try check for updates in the background, we wait for the other instances to exit. There is a timeout on this process (measured across application restarts). If the timeout expires, we will check for updates anyways.
    - If there are still multiple instances running when we go to show the update notification, we don't show the update badge until the doorhanger (popup) notification is shown. When it is shown, we show [different message text](https://searchfox.org/mozilla-central/rev/ea1234192518e01694a88eac8ff090e4cadf5ca4/browser/locales/en-US/browser/appMenuNotifications.ftl#39).
- Technically there is a small race condition in the implementation of `nsIUpdateSyncManager`. We have to [release our read lock](https://searchfox.org/mozilla-central/rev/ea1234192518e01694a88eac8ff090e4cadf5ca4/toolkit/xre/MultiInstanceLock.cpp#202-205) to try to take a write lock or else taking the write lock will always fail.

IIRC, we originally wanted `nsIUpdateSyncManager` to wait for other instances to close between downloading the update and setting the necessary flags that allow it to be installed on startup. But this would have been much more difficult because that would probably have required adding another state to the update state machine. Which would mean that we would probably have to look at basically every time that we do anything with that state and make sure that it still makes sense in the context of the new state machine. So we went with a different implementation that didn't involve having to do that.
I have spent a fair amount of time looking into this on multiple occasions because I can never seem to remember exactly how it works or why it does what it does. This question prompted me to do this again today. :nalexander beat me to actually answering the question, but I want to leave a record of what this does and why, mostly to make it easier on myself the next time I need to look into this.

Firefox has two related things going on with regard to checking for other instances. The [update mutex](https://searchfox.org/mozilla-central/rev/ea1234192518e01694a88eac8ff090e4cadf5ca4/toolkit/mozapps/update/UpdateService.jsm#627) and `nsIUpdateSyncManager`.

The update mutex:
- Has existed for a long time.
- Works similarly to a normal mutex, but is automatically closed if Firefox crashes.
- Is locked when an installation of Firefox tries to update.
- If it cannot be acquired, it means that another instance of Firefox is handling update, so the update system pretty much lets the other instance handle it.
- Currently this exists only on Windows. We may eventually add it to macOS as part of enabling Background Update.

Whereas `nsIUpdateSyncManager`:
- Was created more recently (in this bug).
- Is implemented via a read/write lock system. Each Firefox instance takes a read lock. The write lock can only be taken if there are no other instances with read locks. (Note that I only checked the Windows implementation when I wrote this. I seem to recall that we do slightly different things on other OS's, but I believe they work in similar ways)
- A read lock is taken when Firefox starts. This allows `nsIUpdateSyncManager` to be able to say pretty definitively if any other instances are running, not just if any are updating.
- `nsIUpdateSyncManager` reporting another instance running has a couple of effects.
    - It causes the update interfaces to indicate that update is being handled by another instance. This message isn't quite correct, but the intention is basically correct since if you have multiple instances open, it's not the best time to update.
    - If/when we try check for updates in the background, we wait for the other instances to exit. There is a timeout on this process (measured across application restarts). If the timeout expires, we will check for updates anyways.
    - If there are still multiple instances running when we go to show the update notification, we don't show the update badge until the doorhanger (popup) notification is shown. When it is shown, we show [different message text](https://searchfox.org/mozilla-central/rev/ea1234192518e01694a88eac8ff090e4cadf5ca4/browser/locales/en-US/browser/appMenuNotifications.ftl#39).
- Technically there is a small race condition in the implementation of `nsIUpdateSyncManager`. We have to [release our read lock](https://searchfox.org/mozilla-central/rev/ea1234192518e01694a88eac8ff090e4cadf5ca4/toolkit/xre/MultiInstanceLock.cpp#202-205) to try to take a write lock or else taking the write lock will always fail.

IIRC, we originally wanted `nsIUpdateSyncManager` to wait for other instances to close between downloading the update and setting the necessary flags that allow it to be installed on startup. But this would have been much more difficult because that would probably have required adding another state to the update state machine. Which would mean that we would probably have to look at basically every time that we do anything with that state and make sure that it still makes sense in the context of the new state machine. So we went with a different implementation that didn't involve having to do that.

Back to Bug 1553982 Comment 26