Skip to content

Commit

Permalink
Make callback manager thread safe again
Browse files Browse the repository at this point in the history
Fixes #1424
  • Loading branch information
xPaw committed Sep 10, 2024
1 parent b41b923 commit 48f5000
Showing 1 changed file with 28 additions and 11 deletions.
39 changes: 28 additions & 11 deletions SteamKit2/SteamKit2/Steam/SteamClient/CallbackMgr/CallbackMgr.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public sealed class CallbackManager : ICallbackMgrInternals
{
SteamClient client;

List<CallbackBase> registeredCallbacks;
CallbackBase[] registeredCallbacks = [];



Expand All @@ -34,8 +34,6 @@ public CallbackManager( SteamClient client )
{
ArgumentNullException.ThrowIfNull( client );

registeredCallbacks = [];

this.client = client;
}

Expand Down Expand Up @@ -142,18 +140,42 @@ public IDisposable Subscribe<TCallback>( Action<TCallback> callbackFunc )

void ICallbackMgrInternals.Register( CallbackBase call )
{
if ( registeredCallbacks.Contains( call ) )
var oldCallbacks = registeredCallbacks;

if ( Array.IndexOf( oldCallbacks, call ) != -1 )
return;

// Create a new array for Handle() to be thread safe
var newCallbacks = new CallbackBase[ oldCallbacks.Length + 1 ];
Array.Copy( oldCallbacks, newCallbacks, oldCallbacks.Length );
newCallbacks[ ^1 ] = call;

Interlocked.Exchange( ref registeredCallbacks, newCallbacks );
}

void ICallbackMgrInternals.Unregister( CallbackBase call )
{
var oldCallbacks = registeredCallbacks;
var oldIndex = Array.IndexOf( oldCallbacks, call );

if ( oldIndex < 0 )
return;

registeredCallbacks.Add( call );
var newCallbacks = new CallbackBase[ oldCallbacks.Length - 1 ];

Array.Copy( oldCallbacks, 0, newCallbacks, 0, oldIndex );
Array.Copy( oldCallbacks, oldIndex + 1, newCallbacks, oldIndex, oldCallbacks.Length - oldIndex - 1 );

Interlocked.Exchange( ref registeredCallbacks, newCallbacks );
}

void Handle( ICallbackMsg call )
{
var callbacks = registeredCallbacks;
var type = call.GetType();

// find handlers interested in this callback
foreach ( var callback in registeredCallbacks )
foreach ( var callback in callbacks )
{
if ( callback.CallbackType.IsAssignableFrom( type ) )
{
Expand All @@ -162,11 +184,6 @@ void Handle( ICallbackMsg call )
}
}

void ICallbackMgrInternals.Unregister( CallbackBase call )
{
registeredCallbacks.Remove( call );
}

sealed class Subscription : IDisposable
{
public Subscription( CallbackBase call, ICallbackMgrInternals manager )
Expand Down

0 comments on commit 48f5000

Please sign in to comment.