Squirrel.windows: Squirrel leaking mutex?

Created on 3 Feb 2016  路  31Comments  路  Source: Squirrel/Squirrel.Windows

Sometimes on update I get the guy below.
Update completes successfully, just this message dialog is shown.

Message: An unhandled exception of type 'System.Threading.AbandonedMutexException' occurred in Squirrel.dll
Additional information: Leaked a Mutex!

Squirrel.dll!Squirrel.SingleGlobalInstance.~SingleGlobalInstance() Unknown

The update code is almost out of the box:

Task.Run(async () =>
            {
                try
                {
                    using (var mgr = new UpdateManager(@"SOMEWHERE"))
                    {
                        var re = await mgr.UpdateApp();
                        if(re != null)
                        {
                            UpdateManager.RestartApp();
                        }
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            });

Most helpful comment

for UpdateManager.GitHubUpdateManager, dispose the reult works for me
mgr = UpdateManager.GitHubUpdateManager(WPFView.Properties.Settings.Default.UpdatePath);
using (var result = await mgr)
{
await result.UpdateApp();
}
the code in the document doesn't work
using (var mgr = UpdateManager.GitHubUpdateManager("https://github.com/myuser/myapp"))
{
await mgr.Result.UpdateApp();
}

All 31 comments

It is probably happening becuase I'm calling RestartApp before UpdateManager gets disposed, correct?

It is probably happening becuase I'm calling RestartApp before UpdateManager gets disposed, correct?

I thought we fixed this, hm

I'm also having this problem. It occurs when running the app via Visual Studio (in debug mode). Not sure if it happens with the built version yet.

Yes I see the issue with the built application too. In my case I think I may be doing something wrong though.

I've read that the Update manager needs to be disposed. Could this be the cause of the issue the OP and I are seeing? If so could you point to an example of how to do this?

As I said in second comment, moving RestartApp out of using block does the trick.:)

That's odd - I'm not even calling RestartApp(). However when I close the app I get the exception about a leaking Mutex

@WillsB3 Are you disposing UpdateManager at all?

I don't think so.

My code is literally almost copy pasted from the examples in the docs.

``` C#
static class Program
{
private static Logger logger = LogManager.GetCurrentClassLogger();

    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
        Task.Run(async () => {
            try {
                using (var mgr = UpdateManager.GitHubUpdateManager("https://github.com/WillsB3/WOAI-P3D-Installer")) {
                    // Note, in most of these scenarios, the app exits after this method completes!
                    SquirrelAwareApp.HandleEvents(
                        onInitialInstall: v => {
                            mgr.Result.CreateShortcutForThisExe();
                            logger.Info("OnInitialInstall: " + v);
                        },
                        onAppUpdate: v => {
                            mgr.Result.CreateShortcutForThisExe();
                            logger.Info("OnAppUpdate: " + v);
                        },
                        onAppUninstall: v => {
                            mgr.Result.RemoveShortcutForThisExe();
                            logger.Info("OnAppUninstall: " + v);
                        },
                        onFirstRun: () => {
                            logger.Info("OnFirstRun");
                        }
                    );

                    await mgr.Result.UpdateApp();
                }
            } catch (Exception ex) {
                logger.Warn("Update check failed: " + ex);
            }
        });

        NLog.GlobalDiagnosticsContext.Set("logName", DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss"));

        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Main());
    }

}

```

I'm new to the language so It's probable I'm doing something wrong though!

@WillsB3 We'll need to revise this code, you shouldn't have this wrapped in Task.Run.

OK - well as I say I just lifted the basics from the GitHub manager docs.

Is there a more concrete example of how to use Squirrel? I'm now not using the Easy Mode since I want to be able to update my basic UI with a message if an update is available, or is installing. If you know of any .net apps that do this and are Open Source I'd be grateful for a pointer in the right direction :).

Additionally, I don't want to clog up your issue(s) with my specific implementation questions - so if there's a better place for me to go get help with that then feel free to point me there also :+1:

@WillsB3 Ironically, the vast majority of OSS examples I have are for non-C# apps in Electron, which is Unfortunate. Reading the Easy Mode code though is super instructive, because it tells you the three main pieces of checking for updates (i.e. Get update info => Download files => Apply them).

so if there's a better place for me to go get help with that then feel free to point me there also

nbd, or you can join the Slack chat if you drop me your Email address

@paulcbetts Thanks. I sent you an e-mail but forgot to put something in the subject so it may have gone into your spam folder. Failing that my e-mail is on my GitHub Profile - would be more than willing to move this discussion to Slack if you think that's less Noisy for the project :+1:

I've just revised my update code and I'm still seeing the same issue when closing the applications main form. I've adapted my new code from reading the EasyModeMixin code and hopefully the logic is better (still trying to get my head around Tasks and async behaviour in C# / .Net).

Edit: Actually I see this error at random times when my application is performing processing too. I think I've done something weird with the threading. Any pointers would be appreciated.

Same thing after application closed

I've just got hold of Squirrel.Windows and am experiencing similar issues to those mentioned above.
Looking at the code, I see plenty of calls to acquireUpdateLock, which returns an IDisposable of the lock. The dispose method would dispose of the file handle (fh) and delete the file at normal runtime. In unit test mode this behaviour does not occur, so issues don't show up in test mode.
The issue seems to be that having a using statement does _not_ cause the UpdateManager.Dispose() method to be called immediately. It seems Dispose must be called explicitly without using statement.
NB It's critical to ensure that any potential exceptions are handled in such a way that UpdateManager.Dispose() is called no matter what.

NB This behaviour is what's observed in Debug mode - might be different in Release mode

@paulcbetts
When is this going to be addressed. @martin0 findings are exactly what I discovered. Look Here: https://github.com/Squirrel/Squirrel.Windows/blob/master/src/Squirrel/UpdateManager.cs#L232

Check this out: https://msdn.microsoft.com/en-us/library/b1yfkh5e(v=vs.110).aspx

X AVOID throwing an exception from within Dispose(bool) except under critical situations where the containing process has been corrupted (leaks, inconsistent shared state, etc.).

If Dispose could raise an exception, further finally-block cleanup logic will not execute. To work around this, the user would need to wrap every call to Dispose (within the finally block!) in a try block, which leads to very complex cleanup handlers.

Also please check out the document on best practices for implementing IDisposable. It seems to be that the implementation on UpdateManager is not correct. Ive seen several open issues but with workarounds not addressing this bug.

Check out this article:
https://blogs.msdn.microsoft.com/tom/2008/04/25/understanding-when-to-use-a-finalizer-in-your-net-class/

I have the same issue

hi,
I have the same issue but a found a curious solution.

exemple code :

public async Task<bool> Check() { using (this.updater = new UpdateManager(this._url.ToString())) { var val = await this._updater.CheckForUpdate(); } //some code return result; }

throw mutex exception;

But whith this code not;
` public async Task Check()
{

        using (this.updater = new UpdateManager(this._url.ToString()))
        {
           var val = await this._updater.CheckForUpdate();
        }
        //some code
        this._updater = null;
        GC.WaitForFullGCComplete();
        return result;
    }`

I don't have any exception throw

Workaround described by @Nidkfr is working for me. Not sure why we have this exception however.

Same error here using UpdateManager.GitHubUpdateManager.

CLR20r3
Squirrel
1.5.2.0
System.Threading.AbandonedMutex

Have the same Issue. Using UpdateManager.GitHubUpdateManager and UpdateManager.RestartApp();.
None of the above workarounds seem to work for me. :/

```c#
using (var mgr = UpdateManager.GitHubUpdateManager("https://github.com/user/repo").Result)
{
var updateInfo = mgr.CheckForUpdate().Result;
if (updateInfo.ReleasesToApply.Any())
{
await mgr.UpdateApp();
updated = true;
}
}

if (updated)
UpdateManager.RestartApp();
```

Every example I've found of this is user error, you're checking for updates but closing the app before it completes. This is a bug in your app - killing the app while updates are applying is bad.

If anyone can prove that they are Doing It Right and they're still hitting this bug, please create a new bug

then can you show us an example of doing it the right way?

Just like my example but with await CheckForUpdate instead of mgr.CheckForUpdate().Result 馃檲
BR

@longlostbro The problem is that it's highly dependent on your application, but in general, if your app's Quit menu doesn't have logic for "If the update is running, wait on it before we exit", this is probably what's happening.

for UpdateManager.GitHubUpdateManager, dispose the reult works for me
mgr = UpdateManager.GitHubUpdateManager(WPFView.Properties.Settings.Default.UpdatePath);
using (var result = await mgr)
{
await result.UpdateApp();
}
the code in the document doesn't work
using (var mgr = UpdateManager.GitHubUpdateManager("https://github.com/myuser/myapp"))
{
await mgr.Result.UpdateApp();
}

using await mgr.Result.UpdateApp() (that is mix using asyn and syn) on UI Thread Causes deadlock
http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html

Same happens here. Used Sample-Code.

I think I'm still having the same issue; I moved the UpdateManager call out of Program.cs into an async task calling by my WinForm application. Now, when I close my application (presumably before the async task has completed), I get the leaked mutex exception.

I am calling UpdateManager inside a using() block:

private async void UpdateIfAvailable()
        {
            lastUpdateCheck = DateTime.Now;
            _logger.Debug("Checking remote server for update.");
            try
            {
                using (var mgr = new UpdateManager("XXXXXXX"))
                {
                    await mgr.UpdateApp();
                }
            }
            catch (Exception ex)
            {
                _logger.Debug(ex.Message);
            }
        }

@asfarley Yep, you've got the same problem. Here's one straightforward way to solve it:

public async Task UpdateIfAvailable() {
    updateInProgress = RealUpdateIfAvailable();
    await updateInProgress;
}

public async Task WaitForUpdatesOnShutdown() {
    // We don't actually care about errors here, only completion
    await updateInProgress.ContinueWith(ex => {}); 
}

Task updateInProgress = Task.FromResult(true);
private async Task RealUpdateIfAvailable() {
    lastUpdateCheck = DateTime.Now;
    _logger.Debug("Checking remote server for update.");
    try {
        using (var mgr = new UpdateManager("XXXXXXX")) {
            await mgr.UpdateApp();
        }
    } catch (Exception ex) {
        _logger.Debug(ex.Message);
    }
}


/// Now, in your shutdown code

async void ShutdownTheApp() {
    allTheWindows.ForEach(x => x.Close());
    await WaitForUpdatesOnShutdown();

    Application.Quit();
}
Was this page helpful?
0 / 5 - 0 ratings

Related issues

estyfen picture estyfen  路  4Comments

joshiji picture joshiji  路  6Comments

frederikolsen88 picture frederikolsen88  路  4Comments

CDAGaming picture CDAGaming  路  4Comments

dennisameling picture dennisameling  路  3Comments