mirror of
https://github.com/goatcorp/Dalamud.git
synced 2026-02-17 13:27:43 +01:00
Merge remote-tracking branch 'upstream/master' into feature/inotificationmanager
This commit is contained in:
commit
033a57d19d
51 changed files with 3594 additions and 1284 deletions
|
|
@ -1,6 +1,7 @@
|
|||
using System.Linq;
|
||||
|
||||
using Dalamud.Game;
|
||||
using Dalamud.Game.Gui.ContextMenu;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Serilog;
|
||||
|
||||
|
|
@ -99,6 +100,23 @@ internal static class EventHandlerExtensions
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Replacement for Invoke() on OnMenuOpenedDelegate to catch exceptions that stop event propagation in case
|
||||
/// of a thrown Exception inside of an invocation.
|
||||
/// </summary>
|
||||
/// <param name="openedDelegate">The OnMenuOpenedDelegate in question.</param>
|
||||
/// <param name="argument">Templated argument for Action.</param>
|
||||
public static void InvokeSafely(this IContextMenu.OnMenuOpenedDelegate? openedDelegate, MenuOpenedArgs argument)
|
||||
{
|
||||
if (openedDelegate == null)
|
||||
return;
|
||||
|
||||
foreach (var action in openedDelegate.GetInvocationList().Cast<IContextMenu.OnMenuOpenedDelegate>())
|
||||
{
|
||||
HandleInvoke(() => action(argument));
|
||||
}
|
||||
}
|
||||
|
||||
private static void HandleInvoke(Action act)
|
||||
{
|
||||
try
|
||||
|
|
|
|||
90
Dalamud/Utility/ThreadBoundTaskScheduler.cs
Normal file
90
Dalamud/Utility/ThreadBoundTaskScheduler.cs
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Dalamud.Utility;
|
||||
|
||||
/// <summary>
|
||||
/// A task scheduler that runs tasks on a specific thread.
|
||||
/// </summary>
|
||||
internal class ThreadBoundTaskScheduler : TaskScheduler
|
||||
{
|
||||
private const byte Scheduled = 0;
|
||||
private const byte Running = 1;
|
||||
|
||||
private readonly ConcurrentDictionary<Task, byte> scheduledTasks = new();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ThreadBoundTaskScheduler"/> class.
|
||||
/// </summary>
|
||||
/// <param name="boundThread">The thread to bind this task scheduelr to.</param>
|
||||
public ThreadBoundTaskScheduler(Thread? boundThread = null)
|
||||
{
|
||||
this.BoundThread = boundThread;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the thread this task scheduler is bound to.
|
||||
/// </summary>
|
||||
public Thread? BoundThread { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether we're on the bound thread.
|
||||
/// </summary>
|
||||
public bool IsOnBoundThread => Thread.CurrentThread == this.BoundThread;
|
||||
|
||||
/// <summary>
|
||||
/// Runs queued tasks.
|
||||
/// </summary>
|
||||
public void Run()
|
||||
{
|
||||
foreach (var task in this.scheduledTasks.Keys)
|
||||
{
|
||||
if (!this.scheduledTasks.TryUpdate(task, Running, Scheduled))
|
||||
continue;
|
||||
|
||||
_ = this.TryExecuteTask(task);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override IEnumerable<Task> GetScheduledTasks()
|
||||
{
|
||||
return this.scheduledTasks.Keys;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void QueueTask(Task task)
|
||||
{
|
||||
this.scheduledTasks[task] = Scheduled;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override bool TryDequeue(Task task)
|
||||
{
|
||||
if (!this.scheduledTasks.TryRemove(task, out _))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
|
||||
{
|
||||
if (!this.IsOnBoundThread)
|
||||
return false;
|
||||
|
||||
if (taskWasPreviouslyQueued && !this.scheduledTasks.TryUpdate(task, Running, Scheduled))
|
||||
return false;
|
||||
|
||||
_ = this.TryExecuteTask(task);
|
||||
return true;
|
||||
}
|
||||
|
||||
private new bool TryExecuteTask(Task task)
|
||||
{
|
||||
var r = base.TryExecuteTask(task);
|
||||
this.scheduledTasks.Remove(task, out _);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Dalamud.Utility;
|
||||
|
||||
|
|
@ -19,6 +20,7 @@ public static class ThreadSafety
|
|||
/// Throws an exception when the current thread is not the main thread.
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException">Thrown when the current thread is not the main thread.</exception>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void AssertMainThread()
|
||||
{
|
||||
if (!threadStaticIsMainThread)
|
||||
|
|
@ -31,6 +33,7 @@ public static class ThreadSafety
|
|||
/// Throws an exception when the current thread is the main thread.
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException">Thrown when the current thread is the main thread.</exception>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void AssertNotMainThread()
|
||||
{
|
||||
if (threadStaticIsMainThread)
|
||||
|
|
@ -39,6 +42,15 @@ public static class ThreadSafety
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary><see cref="AssertMainThread"/>, but only on debug compilation mode.</summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void DebugAssertMainThread()
|
||||
{
|
||||
#if DEBUG
|
||||
AssertMainThread();
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Marks a thread as the main thread.
|
||||
/// </summary>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue