1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-14 23:52:57 +08:00

Add flag to guard against deadlocks during blocking operations

This commit is contained in:
Dean Herbert 2022-01-26 17:09:28 +09:00
parent 11f0f3c17d
commit 791ea0308f

View File

@ -89,10 +89,15 @@ namespace osu.Game.Database
private Realm? updateRealm; private Realm? updateRealm;
private bool isSendingNotificationResetEvents;
public Realm Realm => ensureUpdateRealm(); public Realm Realm => ensureUpdateRealm();
private Realm ensureUpdateRealm() private Realm ensureUpdateRealm()
{ {
if (isSendingNotificationResetEvents)
throw new InvalidOperationException("Cannot retrieve a realm context from a notification callback during a blocking operation.");
if (!ThreadSafety.IsUpdateThread) if (!ThreadSafety.IsUpdateThread)
throw new InvalidOperationException(@$"Use {nameof(getRealmInstance)} when performing realm operations from a non-update thread"); throw new InvalidOperationException(@$"Use {nameof(getRealmInstance)} when performing realm operations from a non-update thread");
@ -614,8 +619,20 @@ namespace osu.Game.Database
// calls above. // calls above.
syncContext?.Send(_ => syncContext?.Send(_ =>
{ {
foreach (var action in notificationsResetMap.Values) // Flag ensures that we don't get in a deadlocked scenario due to a callback attempting to access `RealmAccess.Realm` or `RealmAccess.Run`
action(); // and hitting `realmRetrievalLock` a second time. Generally such usages should not exist, and as such we throw when an attempt is made
// to use in this fashion.
isSendingNotificationResetEvents = true;
try
{
foreach (var action in notificationsResetMap.Values)
action();
}
finally
{
isSendingNotificationResetEvents = false;
}
}, null); }, null);
const int sleep_length = 200; const int sleep_length = 200;