diff --git a/TGS.Server/Instance/Instance.cs b/TGS.Server/Instance/Instance.cs index e28d58dc72..a5663c1bed 100644 --- a/TGS.Server/Instance/Instance.cs +++ b/TGS.Server/Instance/Instance.cs @@ -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); } + /// + /// Dumps the status of all locks in the + /// + 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); + } + /// public string Version() { diff --git a/TGS.Server/Instance/Interop.cs b/TGS.Server/Instance/Interop.cs index 1cbe56e7fc..b56bc27251 100644 --- a/TGS.Server/Instance/Interop.cs +++ b/TGS.Server/Instance/Interop.cs @@ -65,6 +65,8 @@ namespace TGS.Server List 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(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(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); } }); }