Khaine
Khaine

Reputation: 335

Win 10 IOT thread deadlocking in UWP

What I want to do: - synchronously (or even asynchronously) load settings from USB drive before first page loads

What I did: - in OnLaunched method for App.xaml.cs I invoked this static function:

public static async void LoadSettings(string folderName = "Config", string fileName = "Settings.xml")
{
    try
    {
    StorageFile configFile = null;
    // scan through all devices
    foreach (var device in await KnownFolders.RemovableDevices.GetFoldersAsync().AsTask().ConfigureAwait(false))
    {
        // folder that should have configuration
        var configFolder = await device.GetFolderAsync(folderName).AsTask().ConfigureAwait(false);

        if (configFile != null && configFolder != null && await configFolder.GetFileAsync(fileName).AsTask().ConfigureAwait(false) != null)
        {
            throw new Exception("More than one configuration file detected. First found configuration file will be used.");
        }
        else
            configFile = await configFolder.GetFileAsync(fileName).AsTask().ConfigureAwait(false);
    }

    if (configFile == null)
        throw new Exception("Configuration file was not found, please insert device with proper configuration path.");

    string settingString = await FileIO.ReadTextAsync(configFile).AsTask().ConfigureAwait(false);

    XmlSerializer serializer = new XmlSerializer(typeof(Settings));
    using (TextReader reader = new StringReader(settingString))
    {
        AppSettings = (Settings)serializer.Deserialize(reader); // store settings in some static variable
    }
}
catch (Exception e)
{

    //return await Task.FromResult<string>(e.Message);
}

//return await Task.FromResult<string>(null);
}

As you can see right now it's async void method, so I don't even want to synchronize it in any way with UI thread. It should just fire and do something. With ConfigureAwait(false) I want to be sure that it will never try to return to context. These returns at the end are remnants of other things I tried (I wanted to do this better way, this is the most primitive solution and it still doesn't work).

Anyway, because that's where the fun begins: everything works well when I debug application on local machine with Win 10. And I get deadlocked thread on Win 10 IOT installed on Raspberry Pi 3 (I installed it from the scratch today, last version).

But deadlock is not the weirdest thing. Weirdest thing is when it appears.

Like I said, invocation of this method looks like that:

protected override void OnLaunched(LaunchActivatedEventArgs e)
{
        Configuration.Settings.LoadSettings();

After that everything in this method goes normally, so I navigate to my first page somewhere below:

if (e.PrelaunchActivated == false)
{
    if (rootFrame.Content == null)
    {
        rootFrame.Navigate(typeof(LogScreen), e.Arguments);
    }

    Window.Current.Activate();
}

Everything still works. User needs to write his code, I check if this code is available in settings and after that user can press "OK" to move to next page. Somewhere in LogScreenViewModel this method is responsible for that:

private void GoForward(bool isValid)
{
    try
    {
        _navigationService.NavigateTo("MainPage"); // it's SimpleIoc navigation from MVVMLight
    }
    catch (Exception e)
    {
        Debug.WriteLine($"ERROR: {e.Message}");
    }
}

And deadlock happens when _navigationService.NavigateTo("MainPage") is reached. Basically right now UI thread freezes. If I wait for long enough I will see catched exception in Output saying that messenger seemed occupied (I can't show the screen because I don't have access to that Raspberry right now) and after some timeout this thread was killed (like 30 seconds or something) - after that UI thread unlocks and application proceeds to MainPage. It doesn't happen on PC - MainPage appears immediately, no exceptions, no deadlocks.

I tried waiting on first page for like 1 minute to check if some deadlock exception would fire on it's own - but it doesn't. It will fire ONLY after I try to proceed to next page.

What else I tried instead of this fire-and-forget approach:

What am I missing? What else can I try? Because to be honest right now it looks to me that Win 10 IOT .NET runtime is bugged or something.

Upvotes: 0

Views: 235

Answers (1)

Khaine
Khaine

Reputation: 335

I think I resolved the issue. This code was generally speaking not mine and after some digging I noticed that someone before me tried to list some other external devices while navigating to MainPage. It was not really async-safe code (someone probably wasn't aware of synchronization context) and it worked on Win 10 only because on desktop it was looking for COM0 device and I only have COM2, so method causing trouble was not even invoked at all.

I still have no idea how related it was to my configuration (because it somehow was working without it), but after I fixed issues with this old not-async-safe code it started to behave as expected.

Upvotes: 0

Related Questions