If handle command is called again before the previous invocation finishes it dumps lock statuses

This commit is contained in:
Cyberboss
2017-12-10 11:21:34 -05:00
parent 4b23c15584
commit bfa50211e4
2 changed files with 89 additions and 53 deletions
+18 -1
View File
@@ -1,7 +1,7 @@
using System;
using System.Diagnostics;
using System.IO;
using System.ServiceModel;
using System.Threading;
using TGS.Interface.Components;
namespace TGS.Server
@@ -104,6 +104,23 @@ namespace TGS.Server
return Path.Combine(Config.Directory, path);
}
/// <summary>
/// Dumps the status of all locks in the <see cref="Instance"/>
/// </summary>
public void DumpLocks()
{
var res = Monitor.TryEnter(RepoLock);
string rb;
if (res)
{
rb = RepoBusy.ToString();
Monitor.Exit(RepoLock);
}
else
rb = "UNKNOWN";
Server.Logger.WriteWarning(String.Format("Started HandleCommand with others running! Active locks: Repo: {0}, Byond: {1}, Compiler: {2}, Topic: {3}, Config: {4}, Watchdog: {5}, Chat: {6}, this: {7}, restartLock: {8}, autoUpdateLock: {9}, RepoBusy: {10}", !res, CheckLocked(ByondLock), CheckLocked(CompilerLock), CheckLocked(topicLock), CheckLocked(configLock), CheckLocked(watchdogLock), CheckLocked(ChatLock), CheckLocked(this), CheckLocked(restartLock), CheckLocked(autoUpdateTimer), rb), EventID.CallTracking, LoggingID);
}
/// <inheritdoc />
public string Version()
{
+71 -52
View File
@@ -65,6 +65,8 @@ namespace TGS.Server
List<Command> ServerChatCommands;
int RunningCommandHandlers = 0;
void LoadServerChatCommands()
{
if (DaemonStatus() != DreamDaemonStatus.Online)
@@ -88,72 +90,89 @@ namespace TGS.Server
catch { }
}
static bool CheckLocked(object o)
{
var res = Monitor.TryEnter(o);
if (res)
Monitor.Exit(o);
return !res;
}
//raw command string sent here via world.ExportService
Task HandleCommand(string cmd)
{
return Task.Run(() =>
{
var splits = new List<string>(cmd.Split(' '));
cmd = splits[0];
splits.RemoveAt(0);
bool APIValid;
lock (topicLock)
if (Interlocked.Increment(ref RunningCommandHandlers) > 1)
DumpLocks();
try
{
APIValid = CheckAPIVersionConstraints();
}
var splits = new List<string>(cmd.Split(' '));
cmd = splits[0];
splits.RemoveAt(0);
if (!APIValid && cmd != SRAPIVersion)
return; //SPEAK THE LANGUAGE!!!
bool APIValid;
lock (topicLock)
{
APIValid = CheckAPIVersionConstraints();
}
switch (cmd)
{
case SRIRCBroadcast:
SendMessage("GAME: " + String.Join(" ", splits), MessageType.GameInfo);
break;
case SRKillProcess:
KillMe();
break;
case SRIRCAdminChannelMessage:
SendMessage("RELAY: " + String.Join(" ", splits), MessageType.AdminInfo);
break;
case SRWorldReboot:
WriteInfo("World Rebooted", EventID.WorldReboot);
WriteCurrentDDLog("World rebooted");
ServerChatCommands = null;
ChatConnectivityCheck();
lock (CompilerLock)
{
if (UpdateStaged)
if (!APIValid && cmd != SRAPIVersion)
return; //SPEAK THE LANGUAGE!!!
switch (cmd)
{
case SRIRCBroadcast:
SendMessage("GAME: " + String.Join(" ", splits), MessageType.GameInfo);
break;
case SRKillProcess:
KillMe();
break;
case SRIRCAdminChannelMessage:
SendMessage("RELAY: " + String.Join(" ", splits), MessageType.AdminInfo);
break;
case SRWorldReboot:
WriteInfo("World Rebooted", EventID.WorldReboot);
WriteCurrentDDLog("World rebooted");
ServerChatCommands = null;
ChatConnectivityCheck();
lock (CompilerLock)
{
UpdateStaged = false;
lock (topicLock)
if (UpdateStaged)
{
GameAPIVersion = null; //needs updating
UpdateStaged = false;
lock (topicLock)
{
GameAPIVersion = null; //needs updating
}
WriteInfo("Staged update applied", EventID.ServerUpdateApplied);
}
WriteInfo("Staged update applied", EventID.ServerUpdateApplied);
}
}
break;
case SRAPIVersion:
lock (topicLock)
{
try
break;
case SRAPIVersion:
lock (topicLock)
{
GameAPIVersion = new Version(splits[0]);
if (!CheckAPIVersionConstraints())
throw new Exception();
try
{
GameAPIVersion = new Version(splits[0]);
if (!CheckAPIVersionConstraints())
throw new Exception();
}
catch
{
WriteWarning(String.Format("API version of the game ({0}) is incompatible with the current supported API versions (3.{2}.x.x). Interop disabled.", splits.Count > 1 ? splits[1] : "NULL", AllowedMajorAPIVersion), EventID.APIVersionMismatch);
GameAPIVersion = null;
break;
}
}
catch
{
WriteWarning(String.Format("API version of the game ({0}) is incompatible with the current supported API versions (3.{2}.x.x). Interop disabled.", splits.Count > 1 ? splits[1] : "NULL", AllowedMajorAPIVersion), EventID.APIVersionMismatch);
GameAPIVersion = null;
break;
}
}
//This needs to be done asyncronously otherwise DD won't be able to process it, because it's waiting for THIS THREAD to return
ThreadPool.QueueUserWorkItem(_ => SendCommand(SCAPICompat));
break;
//This needs to be done asyncronously otherwise DD won't be able to process it, because it's waiting for THIS THREAD to return
ThreadPool.QueueUserWorkItem(_ => SendCommand(SCAPICompat));
break;
}
}
finally
{
Interlocked.Decrement(ref RunningCommandHandlers);
}
});
}