diff options
Diffstat (limited to 'OpenSim/Framework/Util.cs')
-rw-r--r-- | OpenSim/Framework/Util.cs | 192 |
1 files changed, 110 insertions, 82 deletions
diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 557f38e..1775fef 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs | |||
@@ -89,9 +89,30 @@ namespace OpenSim.Framework | |||
89 | } | 89 | } |
90 | 90 | ||
91 | /// <summary> | 91 | /// <summary> |
92 | /// Class for delivering SmartThreadPool statistical information | ||
93 | /// </summary> | ||
94 | /// <remarks> | ||
95 | /// We do it this way so that we do not directly expose STP. | ||
96 | /// </remarks> | ||
97 | public class STPInfo | ||
98 | { | ||
99 | public string Name { get; set; } | ||
100 | public STPStartInfo STPStartInfo { get; set; } | ||
101 | public WIGStartInfo WIGStartInfo { get; set; } | ||
102 | public bool IsIdle { get; set; } | ||
103 | public bool IsShuttingDown { get; set; } | ||
104 | public int MaxThreads { get; set; } | ||
105 | public int MinThreads { get; set; } | ||
106 | public int InUseThreads { get; set; } | ||
107 | public int ActiveThreads { get; set; } | ||
108 | public int WaitingCallbacks { get; set; } | ||
109 | public int MaxConcurrentWorkItems { get; set; } | ||
110 | } | ||
111 | |||
112 | /// <summary> | ||
92 | /// Miscellaneous utility functions | 113 | /// Miscellaneous utility functions |
93 | /// </summary> | 114 | /// </summary> |
94 | public class Util | 115 | public static class Util |
95 | { | 116 | { |
96 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 117 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
97 | 118 | ||
@@ -109,7 +130,7 @@ namespace OpenSim.Framework | |||
109 | private static SmartThreadPool m_ThreadPool; | 130 | private static SmartThreadPool m_ThreadPool; |
110 | 131 | ||
111 | // Unix-epoch starts at January 1st 1970, 00:00:00 UTC. And all our times in the server are (or at least should be) in UTC. | 132 | // Unix-epoch starts at January 1st 1970, 00:00:00 UTC. And all our times in the server are (or at least should be) in UTC. |
112 | private static readonly DateTime unixEpoch = | 133 | public static readonly DateTime UnixEpoch = |
113 | DateTime.ParseExact("1970-01-01 00:00:00 +0", "yyyy-MM-dd hh:mm:ss z", DateTimeFormatInfo.InvariantInfo).ToUniversalTime(); | 134 | DateTime.ParseExact("1970-01-01 00:00:00 +0", "yyyy-MM-dd hh:mm:ss z", DateTimeFormatInfo.InvariantInfo).ToUniversalTime(); |
114 | 135 | ||
115 | private static readonly string rawUUIDPattern | 136 | private static readonly string rawUUIDPattern |
@@ -120,6 +141,11 @@ namespace OpenSim.Framework | |||
120 | public static FireAndForgetMethod DefaultFireAndForgetMethod = FireAndForgetMethod.SmartThreadPool; | 141 | public static FireAndForgetMethod DefaultFireAndForgetMethod = FireAndForgetMethod.SmartThreadPool; |
121 | public static FireAndForgetMethod FireAndForgetMethod = DefaultFireAndForgetMethod; | 142 | public static FireAndForgetMethod FireAndForgetMethod = DefaultFireAndForgetMethod; |
122 | 143 | ||
144 | public static bool IsPlatformMono | ||
145 | { | ||
146 | get { return Type.GetType("Mono.Runtime") != null; } | ||
147 | } | ||
148 | |||
123 | /// <summary> | 149 | /// <summary> |
124 | /// Gets the name of the directory where the current running executable | 150 | /// Gets the name of the directory where the current running executable |
125 | /// is located | 151 | /// is located |
@@ -307,6 +333,49 @@ namespace OpenSim.Framework | |||
307 | return Utils.UIntsToLong(X, Y); | 333 | return Utils.UIntsToLong(X, Y); |
308 | } | 334 | } |
309 | 335 | ||
336 | // Regions are identified with a 'handle' made up of its region coordinates packed into a ulong. | ||
337 | // Several places rely on the ability to extract a region's location from its handle. | ||
338 | // Note the location is in 'world coordinates' (see below). | ||
339 | // Region handles are based on the lowest coordinate of the region so trim the passed x,y to be the regions 0,0. | ||
340 | public static ulong RegionWorldLocToHandle(uint X, uint Y) | ||
341 | { | ||
342 | return Utils.UIntsToLong(X, Y); | ||
343 | } | ||
344 | |||
345 | public static ulong RegionLocToHandle(uint X, uint Y) | ||
346 | { | ||
347 | return Utils.UIntsToLong(Util.RegionToWorldLoc(X), Util.RegionToWorldLoc(Y)); | ||
348 | } | ||
349 | |||
350 | public static void RegionHandleToWorldLoc(ulong handle, out uint X, out uint Y) | ||
351 | { | ||
352 | X = (uint)(handle >> 32); | ||
353 | Y = (uint)(handle & (ulong)uint.MaxValue); | ||
354 | } | ||
355 | |||
356 | public static void RegionHandleToRegionLoc(ulong handle, out uint X, out uint Y) | ||
357 | { | ||
358 | uint worldX, worldY; | ||
359 | RegionHandleToWorldLoc(handle, out worldX, out worldY); | ||
360 | X = WorldToRegionLoc(worldX); | ||
361 | Y = WorldToRegionLoc(worldY); | ||
362 | } | ||
363 | |||
364 | // A region location can be 'world coordinates' (meters from zero) or 'region coordinates' | ||
365 | // (number of regions from zero). This measurement of regions relies on the legacy 256 region size. | ||
366 | // These routines exist to make what is being converted explicit so the next person knows what was meant. | ||
367 | // Convert a region's 'world coordinate' to its 'region coordinate'. | ||
368 | public static uint WorldToRegionLoc(uint worldCoord) | ||
369 | { | ||
370 | return worldCoord / Constants.RegionSize; | ||
371 | } | ||
372 | |||
373 | // Convert a region's 'region coordinate' to its 'world coordinate'. | ||
374 | public static uint RegionToWorldLoc(uint regionCoord) | ||
375 | { | ||
376 | return regionCoord * Constants.RegionSize; | ||
377 | } | ||
378 | |||
310 | public static T Clamp<T>(T x, T min, T max) | 379 | public static T Clamp<T>(T x, T min, T max) |
311 | where T : IComparable<T> | 380 | where T : IComparable<T> |
312 | { | 381 | { |
@@ -495,20 +564,18 @@ namespace OpenSim.Framework | |||
495 | 564 | ||
496 | public static int ToUnixTime(DateTime stamp) | 565 | public static int ToUnixTime(DateTime stamp) |
497 | { | 566 | { |
498 | TimeSpan t = stamp.ToUniversalTime() - unixEpoch; | 567 | TimeSpan t = stamp.ToUniversalTime() - UnixEpoch; |
499 | return (int) t.TotalSeconds; | 568 | return (int)t.TotalSeconds; |
500 | } | 569 | } |
501 | 570 | ||
502 | public static DateTime ToDateTime(ulong seconds) | 571 | public static DateTime ToDateTime(ulong seconds) |
503 | { | 572 | { |
504 | DateTime epoch = unixEpoch; | 573 | return UnixEpoch.AddSeconds(seconds); |
505 | return epoch.AddSeconds(seconds); | ||
506 | } | 574 | } |
507 | 575 | ||
508 | public static DateTime ToDateTime(int seconds) | 576 | public static DateTime ToDateTime(int seconds) |
509 | { | 577 | { |
510 | DateTime epoch = unixEpoch; | 578 | return UnixEpoch.AddSeconds(seconds); |
511 | return epoch.AddSeconds(seconds); | ||
512 | } | 579 | } |
513 | 580 | ||
514 | /// <summary> | 581 | /// <summary> |
@@ -976,7 +1043,7 @@ namespace OpenSim.Framework | |||
976 | else if (typeof(T) == typeof(Int32)) | 1043 | else if (typeof(T) == typeof(Int32)) |
977 | val = cnf.GetInt(varname, (int)val); | 1044 | val = cnf.GetInt(varname, (int)val); |
978 | else if (typeof(T) == typeof(float)) | 1045 | else if (typeof(T) == typeof(float)) |
979 | val = cnf.GetFloat(varname, (int)val); | 1046 | val = cnf.GetFloat(varname, (float)val); |
980 | else | 1047 | else |
981 | m_log.ErrorFormat("[UTIL]: Unhandled type {0}", typeof(T)); | 1048 | m_log.ErrorFormat("[UTIL]: Unhandled type {0}", typeof(T)); |
982 | } | 1049 | } |
@@ -1233,7 +1300,7 @@ namespace OpenSim.Framework | |||
1233 | byte[] bytes = | 1300 | byte[] bytes = |
1234 | { | 1301 | { |
1235 | (byte)regionHandle, (byte)(regionHandle >> 8), (byte)(regionHandle >> 16), (byte)(regionHandle >> 24), | 1302 | (byte)regionHandle, (byte)(regionHandle >> 8), (byte)(regionHandle >> 16), (byte)(regionHandle >> 24), |
1236 | (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle << 56), | 1303 | (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle >> 56), |
1237 | (byte)x, (byte)(x >> 8), 0, 0, | 1304 | (byte)x, (byte)(x >> 8), 0, 0, |
1238 | (byte)y, (byte)(y >> 8), 0, 0 }; | 1305 | (byte)y, (byte)(y >> 8), 0, 0 }; |
1239 | return new UUID(bytes, 0); | 1306 | return new UUID(bytes, 0); |
@@ -1244,7 +1311,7 @@ namespace OpenSim.Framework | |||
1244 | byte[] bytes = | 1311 | byte[] bytes = |
1245 | { | 1312 | { |
1246 | (byte)regionHandle, (byte)(regionHandle >> 8), (byte)(regionHandle >> 16), (byte)(regionHandle >> 24), | 1313 | (byte)regionHandle, (byte)(regionHandle >> 8), (byte)(regionHandle >> 16), (byte)(regionHandle >> 24), |
1247 | (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle << 56), | 1314 | (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle >> 56), |
1248 | (byte)x, (byte)(x >> 8), (byte)z, (byte)(z >> 8), | 1315 | (byte)x, (byte)(x >> 8), (byte)z, (byte)(z >> 8), |
1249 | (byte)y, (byte)(y >> 8), 0, 0 }; | 1316 | (byte)y, (byte)(y >> 8), 0, 0 }; |
1250 | return new UUID(bytes, 0); | 1317 | return new UUID(bytes, 0); |
@@ -1317,7 +1384,7 @@ namespace OpenSim.Framework | |||
1317 | ru = "OSX/Mono"; | 1384 | ru = "OSX/Mono"; |
1318 | else | 1385 | else |
1319 | { | 1386 | { |
1320 | if (Type.GetType("Mono.Runtime") != null) | 1387 | if (IsPlatformMono) |
1321 | ru = "Win/Mono"; | 1388 | ru = "Win/Mono"; |
1322 | else | 1389 | else |
1323 | ru = "Win/.NET"; | 1390 | ru = "Win/.NET"; |
@@ -1765,10 +1832,12 @@ namespace OpenSim.Framework | |||
1765 | FireAndForget(callback, null); | 1832 | FireAndForget(callback, null); |
1766 | } | 1833 | } |
1767 | 1834 | ||
1768 | public static void InitThreadPool(int maxThreads) | 1835 | public static void InitThreadPool(int minThreads, int maxThreads) |
1769 | { | 1836 | { |
1770 | if (maxThreads < 2) | 1837 | if (maxThreads < 2) |
1771 | throw new ArgumentOutOfRangeException("maxThreads", "maxThreads must be greater than 2"); | 1838 | throw new ArgumentOutOfRangeException("maxThreads", "maxThreads must be greater than 2"); |
1839 | if (minThreads > maxThreads || minThreads < 2) | ||
1840 | throw new ArgumentOutOfRangeException("minThreads", "minThreads must be greater than 2 and less than or equal to maxThreads"); | ||
1772 | if (m_ThreadPool != null) | 1841 | if (m_ThreadPool != null) |
1773 | throw new InvalidOperationException("SmartThreadPool is already initialized"); | 1842 | throw new InvalidOperationException("SmartThreadPool is already initialized"); |
1774 | 1843 | ||
@@ -1776,7 +1845,7 @@ namespace OpenSim.Framework | |||
1776 | startInfo.ThreadPoolName = "Util"; | 1845 | startInfo.ThreadPoolName = "Util"; |
1777 | startInfo.IdleTimeout = 2000; | 1846 | startInfo.IdleTimeout = 2000; |
1778 | startInfo.MaxWorkerThreads = maxThreads; | 1847 | startInfo.MaxWorkerThreads = maxThreads; |
1779 | startInfo.MinWorkerThreads = 2; | 1848 | startInfo.MinWorkerThreads = minThreads; |
1780 | 1849 | ||
1781 | m_ThreadPool = new SmartThreadPool(startInfo); | 1850 | m_ThreadPool = new SmartThreadPool(startInfo); |
1782 | } | 1851 | } |
@@ -1851,8 +1920,8 @@ namespace OpenSim.Framework | |||
1851 | break; | 1920 | break; |
1852 | case FireAndForgetMethod.SmartThreadPool: | 1921 | case FireAndForgetMethod.SmartThreadPool: |
1853 | if (m_ThreadPool == null) | 1922 | if (m_ThreadPool == null) |
1854 | InitThreadPool(15); | 1923 | InitThreadPool(2, 15); |
1855 | m_ThreadPool.QueueWorkItem(SmartThreadPoolCallback, new object[] { realCallback, obj }); | 1924 | m_ThreadPool.QueueWorkItem((cb, o) => cb(o), realCallback, obj); |
1856 | break; | 1925 | break; |
1857 | case FireAndForgetMethod.Thread: | 1926 | case FireAndForgetMethod.Thread: |
1858 | Thread thread = new Thread(delegate(object o) { realCallback(o); }); | 1927 | Thread thread = new Thread(delegate(object o) { realCallback(o); }); |
@@ -1864,72 +1933,29 @@ namespace OpenSim.Framework | |||
1864 | } | 1933 | } |
1865 | 1934 | ||
1866 | /// <summary> | 1935 | /// <summary> |
1867 | /// Get a thread pool report. | 1936 | /// Get information about the current state of the smart thread pool. |
1868 | /// </summary> | 1937 | /// </summary> |
1869 | /// <returns></returns> | 1938 | /// <returns> |
1870 | public static string GetThreadPoolReport() | 1939 | /// null if this isn't the pool being used for non-scriptengine threads. |
1940 | /// </returns> | ||
1941 | public static STPInfo GetSmartThreadPoolInfo() | ||
1871 | { | 1942 | { |
1872 | string threadPoolUsed = null; | 1943 | if (m_ThreadPool == null) |
1873 | int maxThreads = 0; | 1944 | return null; |
1874 | int minThreads = 0; | ||
1875 | int allocatedThreads = 0; | ||
1876 | int inUseThreads = 0; | ||
1877 | int waitingCallbacks = 0; | ||
1878 | int completionPortThreads = 0; | ||
1879 | |||
1880 | StringBuilder sb = new StringBuilder(); | ||
1881 | if (FireAndForgetMethod == FireAndForgetMethod.SmartThreadPool) | ||
1882 | { | ||
1883 | // ROBUST currently leaves this the FireAndForgetMethod but never actually initializes the threadpool. | ||
1884 | if (m_ThreadPool != null) | ||
1885 | { | ||
1886 | threadPoolUsed = "SmartThreadPool"; | ||
1887 | maxThreads = m_ThreadPool.MaxThreads; | ||
1888 | minThreads = m_ThreadPool.MinThreads; | ||
1889 | inUseThreads = m_ThreadPool.InUseThreads; | ||
1890 | allocatedThreads = m_ThreadPool.ActiveThreads; | ||
1891 | waitingCallbacks = m_ThreadPool.WaitingCallbacks; | ||
1892 | } | ||
1893 | } | ||
1894 | else if ( | ||
1895 | FireAndForgetMethod == FireAndForgetMethod.UnsafeQueueUserWorkItem | ||
1896 | || FireAndForgetMethod == FireAndForgetMethod.UnsafeQueueUserWorkItem) | ||
1897 | { | ||
1898 | threadPoolUsed = "BuiltInThreadPool"; | ||
1899 | ThreadPool.GetMaxThreads(out maxThreads, out completionPortThreads); | ||
1900 | ThreadPool.GetMinThreads(out minThreads, out completionPortThreads); | ||
1901 | int availableThreads; | ||
1902 | ThreadPool.GetAvailableThreads(out availableThreads, out completionPortThreads); | ||
1903 | inUseThreads = maxThreads - availableThreads; | ||
1904 | allocatedThreads = -1; | ||
1905 | waitingCallbacks = -1; | ||
1906 | } | ||
1907 | |||
1908 | if (threadPoolUsed != null) | ||
1909 | { | ||
1910 | sb.AppendFormat("Thread pool used : {0}\n", threadPoolUsed); | ||
1911 | sb.AppendFormat("Max threads : {0}\n", maxThreads); | ||
1912 | sb.AppendFormat("Min threads : {0}\n", minThreads); | ||
1913 | sb.AppendFormat("Allocated threads : {0}\n", allocatedThreads < 0 ? "not applicable" : allocatedThreads.ToString()); | ||
1914 | sb.AppendFormat("In use threads : {0}\n", inUseThreads); | ||
1915 | sb.AppendFormat("Work items waiting : {0}\n", waitingCallbacks < 0 ? "not available" : waitingCallbacks.ToString()); | ||
1916 | } | ||
1917 | else | ||
1918 | { | ||
1919 | sb.AppendFormat("Thread pool not used\n"); | ||
1920 | } | ||
1921 | |||
1922 | return sb.ToString(); | ||
1923 | } | ||
1924 | 1945 | ||
1925 | private static object SmartThreadPoolCallback(object o) | 1946 | STPInfo stpi = new STPInfo(); |
1926 | { | 1947 | stpi.Name = m_ThreadPool.Name; |
1927 | object[] array = (object[])o; | 1948 | stpi.STPStartInfo = m_ThreadPool.STPStartInfo; |
1928 | WaitCallback callback = (WaitCallback)array[0]; | 1949 | stpi.IsIdle = m_ThreadPool.IsIdle; |
1929 | object obj = array[1]; | 1950 | stpi.IsShuttingDown = m_ThreadPool.IsShuttingdown; |
1951 | stpi.MaxThreads = m_ThreadPool.MaxThreads; | ||
1952 | stpi.MinThreads = m_ThreadPool.MinThreads; | ||
1953 | stpi.InUseThreads = m_ThreadPool.InUseThreads; | ||
1954 | stpi.ActiveThreads = m_ThreadPool.ActiveThreads; | ||
1955 | stpi.WaitingCallbacks = m_ThreadPool.WaitingCallbacks; | ||
1956 | stpi.MaxConcurrentWorkItems = m_ThreadPool.Concurrency; | ||
1930 | 1957 | ||
1931 | callback(obj); | 1958 | return stpi; |
1932 | return null; | ||
1933 | } | 1959 | } |
1934 | 1960 | ||
1935 | #endregion FireAndForget Threading Pattern | 1961 | #endregion FireAndForget Threading Pattern |
@@ -2058,8 +2084,10 @@ namespace OpenSim.Framework | |||
2058 | #region Xml Serialization Utilities | 2084 | #region Xml Serialization Utilities |
2059 | public static bool ReadBoolean(XmlTextReader reader) | 2085 | public static bool ReadBoolean(XmlTextReader reader) |
2060 | { | 2086 | { |
2087 | // AuroraSim uses "int" for some fields that are boolean in OpenSim, e.g. "PassCollisions". Don't fail because of this. | ||
2061 | reader.ReadStartElement(); | 2088 | reader.ReadStartElement(); |
2062 | bool result = Boolean.Parse(reader.ReadContentAsString().ToLower()); | 2089 | string val = reader.ReadContentAsString().ToLower(); |
2090 | bool result = val.Equals("true") || val.Equals("1"); | ||
2063 | reader.ReadEndElement(); | 2091 | reader.ReadEndElement(); |
2064 | 2092 | ||
2065 | return result; | 2093 | return result; |
@@ -2148,7 +2176,7 @@ namespace OpenSim.Framework | |||
2148 | /// <param name="secret">the secret part</param> | 2176 | /// <param name="secret">the secret part</param> |
2149 | public static bool ParseUniversalUserIdentifier(string value, out UUID uuid, out string url, out string firstname, out string lastname, out string secret) | 2177 | public static bool ParseUniversalUserIdentifier(string value, out UUID uuid, out string url, out string firstname, out string lastname, out string secret) |
2150 | { | 2178 | { |
2151 | uuid = UUID.Zero; url = string.Empty; firstname = "Unknown"; lastname = "User"; secret = string.Empty; | 2179 | uuid = UUID.Zero; url = string.Empty; firstname = "Unknown"; lastname = "UserUPUUI"; secret = string.Empty; |
2152 | 2180 | ||
2153 | string[] parts = value.Split(';'); | 2181 | string[] parts = value.Split(';'); |
2154 | if (parts.Length >= 1) | 2182 | if (parts.Length >= 1) |
@@ -2282,7 +2310,7 @@ namespace OpenSim.Framework | |||
2282 | { | 2310 | { |
2283 | lock (m_syncRoot) | 2311 | lock (m_syncRoot) |
2284 | { | 2312 | { |
2285 | m_lowQueue.Enqueue(data); | 2313 | q.Enqueue(data); |
2286 | m_s.WaitOne(0); | 2314 | m_s.WaitOne(0); |
2287 | m_s.Release(); | 2315 | m_s.Release(); |
2288 | } | 2316 | } |
@@ -2322,7 +2350,7 @@ namespace OpenSim.Framework | |||
2322 | { | 2350 | { |
2323 | if (m_highQueue.Count > 0) | 2351 | if (m_highQueue.Count > 0) |
2324 | res = m_highQueue.Dequeue(); | 2352 | res = m_highQueue.Dequeue(); |
2325 | else | 2353 | else if (m_lowQueue.Count > 0) |
2326 | res = m_lowQueue.Dequeue(); | 2354 | res = m_lowQueue.Dequeue(); |
2327 | 2355 | ||
2328 | if (m_highQueue.Count == 0 && m_lowQueue.Count == 0) | 2356 | if (m_highQueue.Count == 0 && m_lowQueue.Count == 0) |