mirror of
https://github.com/Facepunch/sbox-public.git
synced 2026-01-13 16:59:38 -05:00
This commit imports the C# engine code and game files, excluding C++ source code. [Source-Commit: ceb3d758046e50faa6258bc3b658a30c97743268]
111 lines
3.1 KiB
C#
111 lines
3.1 KiB
C#
using Sandbox.Engine;
|
|
using Sandbox.Utility;
|
|
using System.Threading;
|
|
|
|
namespace Sandbox.Tasks;
|
|
|
|
internal static partial class SyncContext
|
|
{
|
|
/// <summary>
|
|
/// Current sync context for the main thread. This will be null until <see cref="Init"/> has been
|
|
/// called for the first time.
|
|
/// </summary>
|
|
public static ExpirableSynchronizationContext MainThread { get; private set; }
|
|
|
|
/// <summary>
|
|
/// Current sync context for worker threads. This will be null until <see cref="Init"/> has been
|
|
/// called for the first time.
|
|
/// </summary>
|
|
public static ExpirableSynchronizationContext WorkerThread { get; private set; }
|
|
|
|
/// <summary>
|
|
/// Sets both <see cref="MainThread"/> and <see cref="SynchronizationContext.Current"/> to be a new
|
|
/// instance of <see cref="ExpirableSynchronizationContext"/>. Only has an effect the first time it's called.
|
|
/// </summary>
|
|
public static void Init()
|
|
{
|
|
if ( MainThread != null ) return;
|
|
|
|
MainThread = new ExpirableSynchronizationContext( false );
|
|
WorkerThread = new ExpirableSynchronizationContext( true );
|
|
|
|
SynchronizationContext.SetSynchronizationContext( MainThread );
|
|
}
|
|
|
|
/// <summary>
|
|
/// Invalidates <see cref="MainThread"/> and <see cref="WorkerThread"/>, and replaces
|
|
/// them with a new instance.
|
|
/// Any tasks that try to continue on the old instances will log an error, unless they
|
|
/// are whitelisted with <see cref="ExpirableSynchronizationContext.AllowPersistentTaskMethods"/>.
|
|
/// </summary>
|
|
public static void Reset()
|
|
{
|
|
MainThread = Reset( MainThread );
|
|
WorkerThread = Reset( WorkerThread );
|
|
}
|
|
|
|
private static ExpirableSynchronizationContext Reset( ExpirableSynchronizationContext oldInstance )
|
|
{
|
|
var newInstance = new ExpirableSynchronizationContext( oldInstance.WarnNonYieldingTasks );
|
|
|
|
if ( SynchronizationContext.Current == oldInstance )
|
|
{
|
|
SynchronizationContext.SetSynchronizationContext( newInstance );
|
|
}
|
|
|
|
oldInstance?.Expire( newInstance );
|
|
|
|
newInstance.ProcessQueue();
|
|
|
|
return newInstance;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Run an async task in a synchronous blocking manner.
|
|
/// </summary>
|
|
public static void RunBlocking( Task task )
|
|
{
|
|
ThreadSafe.AssertIsMainThread();
|
|
|
|
while ( !task.IsCompleted )
|
|
{
|
|
EngineLoop.RunAsyncTasks();
|
|
Thread.Yield();
|
|
IToolsDll.Current?.Spin();
|
|
}
|
|
|
|
if ( task.Exception != null )
|
|
throw task.Exception;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Run an async task in a synchronous blocking manner and returns the result.
|
|
/// </summary>
|
|
public static TResult RunBlocking<TResult>( Task<TResult> task )
|
|
{
|
|
ThreadSafe.AssertIsMainThread();
|
|
|
|
while ( !task.IsCompleted )
|
|
{
|
|
EngineLoop.RunAsyncTasks();
|
|
Thread.Yield();
|
|
}
|
|
|
|
if ( task.Exception != null )
|
|
throw task.Exception;
|
|
|
|
return task.Result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Create a scope that sets the current synchronization context to the provided context.
|
|
/// </summary>
|
|
internal static IDisposable Scope( SynchronizationContext context )
|
|
{
|
|
var oldContext = SynchronizationContext.Current;
|
|
SynchronizationContext.SetSynchronizationContext( context );
|
|
|
|
return DisposeAction.Create( () => { SynchronizationContext.SetSynchronizationContext( oldContext ); } );
|
|
}
|
|
}
|