From 134f86e8d5c414409631b25b8c6f0ee45fbd8631 Mon Sep 17 00:00:00 2001 From: David Walter Seikel Date: Thu, 3 Nov 2016 21:44:39 +1000 Subject: Initial update to OpenSim 0.8.2.1 source code. --- OpenSim/Framework/Servers/ServerBase.cs | 381 +++++++++++++++++++++++++++++++- 1 file changed, 376 insertions(+), 5 deletions(-) (limited to 'OpenSim/Framework/Servers/ServerBase.cs') diff --git a/OpenSim/Framework/Servers/ServerBase.cs b/OpenSim/Framework/Servers/ServerBase.cs index 47baac8..07a09e6 100644 --- a/OpenSim/Framework/Servers/ServerBase.cs +++ b/OpenSim/Framework/Servers/ServerBase.cs @@ -29,6 +29,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; +using System.Linq; using System.Reflection; using System.Text; using System.Text.RegularExpressions; @@ -62,6 +63,8 @@ namespace OpenSim.Framework.Servers protected string m_pidFile = String.Empty; + protected ServerStatsCollector m_serverStatsCollector; + /// /// Server version information. Usually VersionInfo + information about git commit, operating system, etc. /// @@ -76,6 +79,11 @@ namespace OpenSim.Framework.Servers protected void CreatePIDFile(string path) { + if (File.Exists(path)) + m_log.ErrorFormat( + "[SERVER BASE]: Previous pid file {0} still exists on startup. Possibly previously unclean shutdown.", + path); + try { string pidstring = System.Diagnostics.Process.GetCurrentProcess().Id.ToString(); @@ -113,6 +121,26 @@ namespace OpenSim.Framework.Servers } } + /// + /// Log information about the circumstances in which we're running (OpenSimulator version number, CLR details, + /// etc.). + /// + public void LogEnvironmentInformation() + { + // FIXME: This should be done down in ServerBase but we need to sort out and refactor the log4net + // XmlConfigurator calls first accross servers. + m_log.InfoFormat("[SERVER BASE]: Starting in {0}", m_startupDirectory); + + m_log.InfoFormat("[SERVER BASE]: OpenSimulator version: {0}", m_version); + + // clr version potentially is more confusing than helpful, since it doesn't tell us if we're running under Mono/MS .NET and + // the clr version number doesn't match the project version number under Mono. + //m_log.Info("[STARTUP]: Virtual machine runtime version: " + Environment.Version + Environment.NewLine); + m_log.InfoFormat( + "[SERVER BASE]: Operating system version: {0}, .NET platform {1}, {2}-bit", + Environment.OSVersion, Environment.OSVersion.Platform, Util.Is64BitProcess() ? "64" : "32"); + } + public void RegisterCommonAppenders(IConfig startupConfig) { ILoggerRepository repository = LogManager.GetRepository(); @@ -219,7 +247,7 @@ namespace OpenSim.Framework.Servers "Show thread status", HandleShow); m_console.Commands.AddCommand( - "General", false, "threads abort", + "Debug", false, "threads abort", "threads abort ", "Abort a managed thread. Use \"show threads\" to find possible threads.", HandleThreadsAbort); @@ -229,11 +257,281 @@ namespace OpenSim.Framework.Servers "Show thread status. Synonym for \"show threads\"", (string module, string[] args) => Notice(GetThreadsReport())); + m_console.Commands.AddCommand ( + "Debug", false, "debug comms set", + "debug comms set serialosdreq true|false", + "Set comms parameters. For debug purposes.", + HandleDebugCommsSet); + + m_console.Commands.AddCommand ( + "Debug", false, "debug comms status", + "debug comms status", + "Show current debug comms parameters.", + HandleDebugCommsStatus); + + m_console.Commands.AddCommand ( + "Debug", false, "debug threadpool set", + "debug threadpool set worker|iocp min|max ", + "Set threadpool parameters. For debug purposes.", + HandleDebugThreadpoolSet); + + m_console.Commands.AddCommand ( + "Debug", false, "debug threadpool status", + "debug threadpool status", + "Show current debug threadpool parameters.", + HandleDebugThreadpoolStatus); + + m_console.Commands.AddCommand( + "Debug", false, "debug threadpool level", + "debug threadpool level 0.." + Util.MAX_THREADPOOL_LEVEL, + "Turn on logging of activity in the main thread pool.", + "Log levels:\n" + + " 0 = no logging\n" + + " 1 = only first line of stack trace; don't log common threads\n" + + " 2 = full stack trace; don't log common threads\n" + + " 3 = full stack trace, including common threads\n", + HandleDebugThreadpoolLevel); + +// m_console.Commands.AddCommand( +// "Debug", false, "show threadpool calls active", +// "show threadpool calls active", +// "Show details about threadpool calls that are still active (currently waiting or in progress)", +// HandleShowThreadpoolCallsActive); + m_console.Commands.AddCommand( - "General", false, "force gc", + "Debug", false, "show threadpool calls complete", + "show threadpool calls complete", + "Show details about threadpool calls that have been completed.", + HandleShowThreadpoolCallsComplete); + + m_console.Commands.AddCommand( + "Debug", false, "force gc", "force gc", "Manually invoke runtime garbage collection. For debugging purposes", HandleForceGc); + + m_console.Commands.AddCommand( + "General", false, "quit", + "quit", + "Quit the application", (mod, args) => Shutdown()); + + m_console.Commands.AddCommand( + "General", false, "shutdown", + "shutdown", + "Quit the application", (mod, args) => Shutdown()); + + ChecksManager.RegisterConsoleCommands(m_console); + StatsManager.RegisterConsoleCommands(m_console); + } + + public void RegisterCommonComponents(IConfigSource configSource) + { + IConfig networkConfig = configSource.Configs["Network"]; + + if (networkConfig != null) + { + WebUtil.SerializeOSDRequestsPerEndpoint = networkConfig.GetBoolean("SerializeOSDRequests", false); + } + + m_serverStatsCollector = new ServerStatsCollector(); + m_serverStatsCollector.Initialise(configSource); + m_serverStatsCollector.Start(); + } + + private void HandleDebugCommsStatus(string module, string[] args) + { + Notice("serialosdreq is {0}", WebUtil.SerializeOSDRequestsPerEndpoint); + } + + private void HandleDebugCommsSet(string module, string[] args) + { + if (args.Length != 5) + { + Notice("Usage: debug comms set serialosdreq true|false"); + return; + } + + if (args[3] != "serialosdreq") + { + Notice("Usage: debug comms set serialosdreq true|false"); + return; + } + + bool setSerializeOsdRequests; + + if (!ConsoleUtil.TryParseConsoleBool(m_console, args[4], out setSerializeOsdRequests)) + return; + + WebUtil.SerializeOSDRequestsPerEndpoint = setSerializeOsdRequests; + + Notice("serialosdreq is now {0}", setSerializeOsdRequests); + } + + private void HandleShowThreadpoolCallsActive(string module, string[] args) + { + List> calls = Util.GetFireAndForgetCallsInProgress().ToList(); + calls.Sort((kvp1, kvp2) => kvp2.Value.CompareTo(kvp1.Value)); + int namedCalls = 0; + + ConsoleDisplayList cdl = new ConsoleDisplayList(); + foreach (KeyValuePair kvp in calls) + { + if (kvp.Value > 0) + { + cdl.AddRow(kvp.Key, kvp.Value); + namedCalls += kvp.Value; + } + } + + cdl.AddRow("TOTAL NAMED", namedCalls); + + long allQueuedCalls = Util.TotalQueuedFireAndForgetCalls; + long allRunningCalls = Util.TotalRunningFireAndForgetCalls; + + cdl.AddRow("TOTAL QUEUED", allQueuedCalls); + cdl.AddRow("TOTAL RUNNING", allRunningCalls); + cdl.AddRow("TOTAL ANONYMOUS", allQueuedCalls + allRunningCalls - namedCalls); + cdl.AddRow("TOTAL ALL", allQueuedCalls + allRunningCalls); + + MainConsole.Instance.Output(cdl.ToString()); + } + + private void HandleShowThreadpoolCallsComplete(string module, string[] args) + { + List> calls = Util.GetFireAndForgetCallsMade().ToList(); + calls.Sort((kvp1, kvp2) => kvp2.Value.CompareTo(kvp1.Value)); + int namedCallsMade = 0; + + ConsoleDisplayList cdl = new ConsoleDisplayList(); + foreach (KeyValuePair kvp in calls) + { + cdl.AddRow(kvp.Key, kvp.Value); + namedCallsMade += kvp.Value; + } + + cdl.AddRow("TOTAL NAMED", namedCallsMade); + + long allCallsMade = Util.TotalFireAndForgetCallsMade; + cdl.AddRow("TOTAL ANONYMOUS", allCallsMade - namedCallsMade); + cdl.AddRow("TOTAL ALL", allCallsMade); + + MainConsole.Instance.Output(cdl.ToString()); + } + + private void HandleDebugThreadpoolStatus(string module, string[] args) + { + int workerThreads, iocpThreads; + + ThreadPool.GetMinThreads(out workerThreads, out iocpThreads); + Notice("Min worker threads: {0}", workerThreads); + Notice("Min IOCP threads: {0}", iocpThreads); + + ThreadPool.GetMaxThreads(out workerThreads, out iocpThreads); + Notice("Max worker threads: {0}", workerThreads); + Notice("Max IOCP threads: {0}", iocpThreads); + + ThreadPool.GetAvailableThreads(out workerThreads, out iocpThreads); + Notice("Available worker threads: {0}", workerThreads); + Notice("Available IOCP threads: {0}", iocpThreads); + } + + private void HandleDebugThreadpoolSet(string module, string[] args) + { + if (args.Length != 6) + { + Notice("Usage: debug threadpool set worker|iocp min|max "); + return; + } + + int newThreads; + + if (!ConsoleUtil.TryParseConsoleInt(m_console, args[5], out newThreads)) + return; + + string poolType = args[3]; + string bound = args[4]; + + bool fail = false; + int workerThreads, iocpThreads; + + if (poolType == "worker") + { + if (bound == "min") + { + ThreadPool.GetMinThreads(out workerThreads, out iocpThreads); + + if (!ThreadPool.SetMinThreads(newThreads, iocpThreads)) + fail = true; + } + else + { + ThreadPool.GetMaxThreads(out workerThreads, out iocpThreads); + + if (!ThreadPool.SetMaxThreads(newThreads, iocpThreads)) + fail = true; + } + } + else + { + if (bound == "min") + { + ThreadPool.GetMinThreads(out workerThreads, out iocpThreads); + + if (!ThreadPool.SetMinThreads(workerThreads, newThreads)) + fail = true; + } + else + { + ThreadPool.GetMaxThreads(out workerThreads, out iocpThreads); + + if (!ThreadPool.SetMaxThreads(workerThreads, newThreads)) + fail = true; + } + } + + if (fail) + { + Notice("ERROR: Could not set {0} {1} threads to {2}", poolType, bound, newThreads); + } + else + { + int minWorkerThreads, maxWorkerThreads, minIocpThreads, maxIocpThreads; + + ThreadPool.GetMinThreads(out minWorkerThreads, out minIocpThreads); + ThreadPool.GetMaxThreads(out maxWorkerThreads, out maxIocpThreads); + + Notice("Min worker threads now {0}", minWorkerThreads); + Notice("Min IOCP threads now {0}", minIocpThreads); + Notice("Max worker threads now {0}", maxWorkerThreads); + Notice("Max IOCP threads now {0}", maxIocpThreads); + } + } + + private static void HandleDebugThreadpoolLevel(string module, string[] cmdparams) + { + if (cmdparams.Length < 4) + { + MainConsole.Instance.Output("Usage: debug threadpool level 0.." + Util.MAX_THREADPOOL_LEVEL); + return; + } + + string rawLevel = cmdparams[3]; + int newLevel; + + if (!int.TryParse(rawLevel, out newLevel)) + { + MainConsole.Instance.OutputFormat("{0} is not a valid debug level", rawLevel); + return; + } + + if (newLevel < 0 || newLevel > Util.MAX_THREADPOOL_LEVEL) + { + MainConsole.Instance.OutputFormat("{0} is outside the valid debug level range of 0.." + Util.MAX_THREADPOOL_LEVEL, newLevel); + return; + } + + Util.LogThreadPool = newLevel; + MainConsole.Instance.OutputFormat("LogThreadPool set to {0}", newLevel); } private void HandleForceGc(string module, string[] args) @@ -575,7 +873,8 @@ namespace OpenSim.Framework.Servers protected string GetVersionText() { - return String.Format("Version: {0} (interface version {1})", m_version, VersionInfo.MajorInterfaceVersion); + return String.Format("Version: {0} (SIMULATION/{1} - SIMULATION/{2})", + m_version, VersionInfo.SimulationServiceVersionSupportedMin, VersionInfo.SimulationServiceVersionSupportedMax); } /// @@ -621,7 +920,68 @@ namespace OpenSim.Framework.Servers sb.AppendFormat("Total threads active: {0}\n\n", totalThreads); sb.Append("Main threadpool (excluding script engine pools)\n"); - sb.Append(Util.GetThreadPoolReport()); + sb.Append(GetThreadPoolReport()); + + return sb.ToString(); + } + + /// + /// Get a thread pool report. + /// + /// + public static string GetThreadPoolReport() + { + string threadPoolUsed = null; + int maxThreads = 0; + int minThreads = 0; + int allocatedThreads = 0; + int inUseThreads = 0; + int waitingCallbacks = 0; + int completionPortThreads = 0; + + StringBuilder sb = new StringBuilder(); + if (Util.FireAndForgetMethod == FireAndForgetMethod.SmartThreadPool) + { + STPInfo stpi = Util.GetSmartThreadPoolInfo(); + + // ROBUST currently leaves this the FireAndForgetMethod but never actually initializes the threadpool. + if (stpi != null) + { + threadPoolUsed = "SmartThreadPool"; + maxThreads = stpi.MaxThreads; + minThreads = stpi.MinThreads; + inUseThreads = stpi.InUseThreads; + allocatedThreads = stpi.ActiveThreads; + waitingCallbacks = stpi.WaitingCallbacks; + } + } + else if ( + Util.FireAndForgetMethod == FireAndForgetMethod.QueueUserWorkItem + || Util.FireAndForgetMethod == FireAndForgetMethod.UnsafeQueueUserWorkItem) + { + threadPoolUsed = "BuiltInThreadPool"; + ThreadPool.GetMaxThreads(out maxThreads, out completionPortThreads); + ThreadPool.GetMinThreads(out minThreads, out completionPortThreads); + int availableThreads; + ThreadPool.GetAvailableThreads(out availableThreads, out completionPortThreads); + inUseThreads = maxThreads - availableThreads; + allocatedThreads = -1; + waitingCallbacks = -1; + } + + if (threadPoolUsed != null) + { + sb.AppendFormat("Thread pool used : {0}\n", threadPoolUsed); + sb.AppendFormat("Max threads : {0}\n", maxThreads); + sb.AppendFormat("Min threads : {0}\n", minThreads); + sb.AppendFormat("Allocated threads : {0}\n", allocatedThreads < 0 ? "not applicable" : allocatedThreads.ToString()); + sb.AppendFormat("In use threads : {0}\n", inUseThreads); + sb.AppendFormat("Work items waiting : {0}\n", waitingCallbacks < 0 ? "not available" : waitingCallbacks.ToString()); + } + else + { + sb.AppendFormat("Thread pool not used\n"); + } return sb.ToString(); } @@ -673,5 +1033,16 @@ namespace OpenSim.Framework.Servers if (m_console != null) m_console.OutputFormat(format, components); } + + public virtual void Shutdown() + { + m_serverStatsCollector.Close(); + ShutdownSpecific(); + } + + /// + /// Should be overriden and referenced by descendents if they need to perform extra shutdown processing + /// + protected virtual void ShutdownSpecific() {} } -} \ No newline at end of file +} -- cgit v1.1