fix(core): Fixes threading issue and adds threadguard (#565)
Setting `m.NetState = null` from a different thread caused `Mobile.Delta` and `NetState.Send` to run from a separate thread which cannot happen. - [X] Fixes this issue - [X] Adds THREADGUARD compiler constant as an option to trace this in the future.
This commit is contained in:
parent
47bbd72e55
commit
529abb4283
2 changed files with 118 additions and 81 deletions
|
|
@ -1447,93 +1447,96 @@ namespace Server
|
|||
}
|
||||
set
|
||||
{
|
||||
if (m_NetState != value)
|
||||
if (m_NetState == value)
|
||||
{
|
||||
m_Map?.OnClientChange(m_NetState, value, this);
|
||||
return;
|
||||
}
|
||||
|
||||
m_Target?.Cancel(this, TargetCancelType.Disconnected);
|
||||
#if THREADGUARD
|
||||
if (Thread.CurrentThread != Core.Thread)
|
||||
{
|
||||
Utility.PushColor(ConsoleColor.Red);
|
||||
Console.WriteLine("Attempting to set Mobile.NetState value from an invalid thread!");
|
||||
Console.WriteLine(new StackTrace());
|
||||
Utility.PopColor();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_Spell?.OnConnectionChanged();
|
||||
m_Map?.OnClientChange(m_NetState, value, this);
|
||||
m_Target?.Cancel(this, TargetCancelType.Disconnected);
|
||||
m_Spell?.OnConnectionChanged();
|
||||
m_NetState?.CancelAllTrades();
|
||||
|
||||
// if (m_Spell != null)
|
||||
// m_Spell.FinishSequence();
|
||||
var box = FindBankNoCreate();
|
||||
|
||||
m_NetState?.CancelAllTrades();
|
||||
if (box?.Opened == true)
|
||||
{
|
||||
box.Close();
|
||||
}
|
||||
|
||||
var box = FindBankNoCreate();
|
||||
m_NetState = value;
|
||||
|
||||
if (box?.Opened == true)
|
||||
if (m_NetState == null)
|
||||
{
|
||||
OnDisconnected();
|
||||
EventSink.InvokeDisconnected(this);
|
||||
|
||||
// Disconnected, start the logout timer
|
||||
if (m_LogoutTimer == null)
|
||||
{
|
||||
box.Close();
|
||||
}
|
||||
|
||||
// REMOVED:
|
||||
// m_Actions.Clear();
|
||||
|
||||
m_NetState = value;
|
||||
|
||||
if (m_NetState == null)
|
||||
{
|
||||
OnDisconnected();
|
||||
EventSink.InvokeDisconnected(this);
|
||||
|
||||
// Disconnected, start the logout timer
|
||||
if (m_LogoutTimer == null)
|
||||
{
|
||||
m_LogoutTimer = Timer.DelayCall(GetLogoutDelay(), Logout);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_LogoutTimer.Stop();
|
||||
m_LogoutTimer.Delay = GetLogoutDelay();
|
||||
m_LogoutTimer.Start();
|
||||
}
|
||||
m_LogoutTimer = Timer.DelayCall(GetLogoutDelay(), Logout);
|
||||
}
|
||||
else
|
||||
{
|
||||
OnConnected();
|
||||
EventSink.InvokeConnected(this);
|
||||
|
||||
// Connected, stop the logout timer and if needed, move to the world
|
||||
|
||||
m_LogoutTimer?.Stop();
|
||||
|
||||
m_LogoutTimer = null;
|
||||
|
||||
if (m_Map == Map.Internal && LogoutMap != null)
|
||||
{
|
||||
Map = LogoutMap;
|
||||
Location = LogoutLocation;
|
||||
}
|
||||
m_LogoutTimer.Stop();
|
||||
m_LogoutTimer.Delay = GetLogoutDelay();
|
||||
m_LogoutTimer.Start();
|
||||
}
|
||||
|
||||
for (var i = Items.Count - 1; i >= 0; --i)
|
||||
{
|
||||
if (i >= Items.Count)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var item = Items[i];
|
||||
|
||||
if (item is SecureTradeContainer)
|
||||
{
|
||||
for (var j = item.Items.Count - 1; j >= 0; --j)
|
||||
{
|
||||
if (j < item.Items.Count)
|
||||
{
|
||||
item.Items[j].OnSecureTrade(this, this, this, false);
|
||||
AddToBackpack(item.Items[j]);
|
||||
}
|
||||
}
|
||||
|
||||
Timer.DelayCall(item.Delete);
|
||||
}
|
||||
}
|
||||
|
||||
DropHolding();
|
||||
OnNetStateChanged();
|
||||
}
|
||||
else
|
||||
{
|
||||
OnConnected();
|
||||
EventSink.InvokeConnected(this);
|
||||
|
||||
// Connected, stop the logout timer and if needed, move to the world
|
||||
m_LogoutTimer?.Stop();
|
||||
|
||||
m_LogoutTimer = null;
|
||||
|
||||
if (m_Map == Map.Internal && LogoutMap != null)
|
||||
{
|
||||
Map = LogoutMap;
|
||||
Location = LogoutLocation;
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = Items.Count - 1; i >= 0; --i)
|
||||
{
|
||||
if (i >= Items.Count)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var item = Items[i];
|
||||
|
||||
if (item is SecureTradeContainer)
|
||||
{
|
||||
for (var j = item.Items.Count - 1; j >= 0; --j)
|
||||
{
|
||||
if (j < item.Items.Count)
|
||||
{
|
||||
item.Items[j].OnSecureTrade(this, this, this, false);
|
||||
AddToBackpack(item.Items[j]);
|
||||
}
|
||||
}
|
||||
|
||||
Timer.DelayCall(item.Delete);
|
||||
}
|
||||
}
|
||||
|
||||
DropHolding();
|
||||
OnNetStateChanged();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -7922,6 +7925,17 @@ namespace Server
|
|||
|
||||
public virtual void Delta(MobileDelta flag)
|
||||
{
|
||||
#if THREADGUARD
|
||||
if (Thread.CurrentThread != Core.Thread)
|
||||
{
|
||||
Utility.PushColor(ConsoleColor.Red);
|
||||
Console.WriteLine("Attempting to queue a delta change from an invalid thread!");
|
||||
Console.WriteLine(new StackTrace());
|
||||
Utility.PopColor();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (m_Map == null || m_Map == Map.Internal || Deleted)
|
||||
{
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ using System;
|
|||
using System.Buffers;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
|
|
@ -453,6 +454,16 @@ namespace Server.Network
|
|||
|
||||
public bool GetSendBuffer(out CircularBuffer<byte> cBuffer)
|
||||
{
|
||||
#if THREADGUARD
|
||||
if (Thread.CurrentThread != Core.Thread)
|
||||
{
|
||||
Utility.PushColor(ConsoleColor.Red);
|
||||
Console.WriteLine("Attempting to get pipe buffer from wrong thread!");
|
||||
Console.WriteLine(new StackTrace());
|
||||
Utility.PopColor();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
var result = SendPipe.Writer.TryGetMemory();
|
||||
cBuffer = new CircularBuffer<byte>(result.Buffer);
|
||||
|
||||
|
|
@ -1056,13 +1067,6 @@ namespace Server.Network
|
|||
return;
|
||||
}
|
||||
|
||||
var m = Mobile;
|
||||
if (m != null)
|
||||
{
|
||||
m.NetState = null;
|
||||
Mobile = null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (_disconnectReason != string.Empty)
|
||||
|
|
@ -1108,9 +1112,28 @@ namespace Server.Network
|
|||
{
|
||||
TraceDisconnect(_disconnectReason, _toString);
|
||||
|
||||
#if THREADGUARD
|
||||
if (Thread.CurrentThread != Core.Thread)
|
||||
{
|
||||
Utility.PushColor(ConsoleColor.Red);
|
||||
Console.WriteLine("Attempting to dispose a netstate from an invalid thread!");
|
||||
Console.WriteLine(new StackTrace());
|
||||
Utility.PopColor();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
RecvPipe.Writer.Close();
|
||||
SendPipe.Writer.Close();
|
||||
|
||||
var m = Mobile;
|
||||
Mobile = null;
|
||||
|
||||
if (m?.NetState == this)
|
||||
{
|
||||
m.NetState = null;
|
||||
}
|
||||
|
||||
var a = Account;
|
||||
|
||||
Gumps.Clear();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue