1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-14 18:33:20 +08:00

Merge branch 'realm-nested-context-creation-deadlock-fix' into realm-integration/skins-rebase

This commit is contained in:
Dean Herbert 2021-11-30 15:56:34 +09:00
commit e83ada40f9
2 changed files with 20 additions and 18 deletions

View File

@ -36,34 +36,36 @@ namespace osu.Game.Tests.Database
});
}
/// <summary>
/// Test to ensure that a `CreateContext` call nested inside a subscription doesn't cause any deadlocks
/// due to context fetching semaphores.
/// </summary>
[Test]
public void TestNestedContextCreation()
public void TestNestedContextCreationWithSubscription()
{
RunTestWithRealm((realmFactory, _) =>
{
var mainContext = realmFactory.Context;
bool callbackRan = false;
var subscription = mainContext.All<RealmBeatmap>().SubscribeForNotifications((sender, changes, error) =>
using (var context = realmFactory.CreateContext())
{
realmFactory.CreateContext();
callbackRan = true;
});
Task.Factory.StartNew(() =>
{
using (var threadContext = realmFactory.CreateContext())
var subscription = context.All<RealmBeatmap>().SubscribeForNotifications((sender, changes, error) =>
{
threadContext.Write(r => r.Add(new RealmBeatmap(CreateRuleset(), new RealmBeatmapDifficulty(), new RealmBeatmapMetadata())));
}
}, TaskCreationOptions.LongRunning | TaskCreationOptions.HideScheduler).Wait();
using (realmFactory.CreateContext())
{
callbackRan = true;
}
});
// will create a context but also run the callback above (Refresh is implicitly run when getting a new context).
realmFactory.CreateContext();
// Force the callback above to run.
using (realmFactory.CreateContext())
{
}
subscription.Dispose();
}
Assert.IsTrue(callbackRan);
subscription.Dispose();
});
}

View File

@ -162,6 +162,7 @@ namespace osu.Game.Database
if (!currentThreadCanCreateContexts.Value)
{
contextCreationLock.Wait();
currentThreadCanCreateContexts.Value = true;
tookSemaphoreLock = true;
}
else
@ -169,7 +170,6 @@ namespace osu.Game.Database
// the semaphore is used to handle blocking of all context creation during certain periods.
// once the semaphore has been taken by this code section, it is safe to create further contexts on the same thread.
// this can happen if a realm subscription is active and triggers a callback which has user code that calls `CreateContext`.
currentThreadCanCreateContexts.Value = true;
}
contexts_created.Value++;