Some collection modified safety in Dispatch (seeing a few exceptions on Rust staging)

This commit is contained in:
Garry Newman 2020-02-28 11:05:27 +00:00
parent 5aeeaa0cd7
commit e6c0167c48

View File

@ -65,30 +65,54 @@ internal static void Init()
SteamAPI_ManualDispatch_Init();
}
/// <summary>
/// Make sure we don't call Frame in a callback - because that'll cause some issues for everyone.
/// </summary>
static bool runningFrame = false;
/// <summary>
/// Calls RunFrame and processes events from this Steam Pipe
/// </summary>
internal static void Frame( HSteamPipe pipe )
{
SteamAPI_ManualDispatch_RunFrame( pipe );
SteamNetworkingUtils.OutputDebugMessages();
{
if ( runningFrame )
return;
CallbackMsg_t msg = default;
while ( SteamAPI_ManualDispatch_GetNextCallback( pipe, ref msg ) )
try
{
try
runningFrame = true;
SteamAPI_ManualDispatch_RunFrame( pipe );
SteamNetworkingUtils.OutputDebugMessages();
CallbackMsg_t msg = default;
while ( SteamAPI_ManualDispatch_GetNextCallback( pipe, ref msg ) )
{
ProcessCallback( msg, pipe == ServerPipe );
}
finally
{
SteamAPI_ManualDispatch_FreeLastCallback( pipe );
try
{
ProcessCallback( msg, pipe == ServerPipe );
}
finally
{
SteamAPI_ManualDispatch_FreeLastCallback( pipe );
}
}
}
finally
{
runningFrame = false;
}
}
/// <summary>
/// To be safe we don't call the continuation functions while iterating
/// the Callback list. This is maybe overly safe because the only way this
/// could be an issue is if the callback list is modified in the continuation
/// which would only happen if starting or shutting down in the callback.
/// </summary>
static List<Action<IntPtr>> actionsToCall = new List<Action<IntPtr>>();
/// <summary>
/// A callback is a general global message
/// </summary>
@ -108,13 +132,22 @@ private static void ProcessCallback( CallbackMsg_t msg, bool isServer )
if ( Callbacks.TryGetValue( msg.Type, out var list ) )
{
actionsToCall.Clear();
foreach ( var item in list )
{
if ( item.server != isServer )
continue;
item.action( msg.Data );
actionsToCall.Add( item.action );
}
foreach ( var action in actionsToCall )
{
action( msg.Data );
}
actionsToCall.Clear();
}
}