diff options
Diffstat (limited to 'OpenSim/Framework/Util.cs')
-rw-r--r-- | OpenSim/Framework/Util.cs | 211 |
1 files changed, 123 insertions, 88 deletions
diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 557f38e..b8b78fa 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs | |||
@@ -58,6 +58,15 @@ namespace OpenSim.Framework | |||
58 | public enum PermissionMask : uint | 58 | public enum PermissionMask : uint |
59 | { | 59 | { |
60 | None = 0, | 60 | None = 0, |
61 | |||
62 | // folded perms | ||
63 | foldedTransfer = 1, | ||
64 | foldedModify = 1 << 1, | ||
65 | foldedCopy = 1 << 2, | ||
66 | |||
67 | foldedMask = 0x07, | ||
68 | |||
69 | // | ||
61 | Transfer = 1 << 13, | 70 | Transfer = 1 << 13, |
62 | Modify = 1 << 14, | 71 | Modify = 1 << 14, |
63 | Copy = 1 << 15, | 72 | Copy = 1 << 15, |
@@ -89,9 +98,30 @@ namespace OpenSim.Framework | |||
89 | } | 98 | } |
90 | 99 | ||
91 | /// <summary> | 100 | /// <summary> |
101 | /// Class for delivering SmartThreadPool statistical information | ||
102 | /// </summary> | ||
103 | /// <remarks> | ||
104 | /// We do it this way so that we do not directly expose STP. | ||
105 | /// </remarks> | ||
106 | public class STPInfo | ||
107 | { | ||
108 | public string Name { get; set; } | ||
109 | public STPStartInfo STPStartInfo { get; set; } | ||
110 | public WIGStartInfo WIGStartInfo { get; set; } | ||
111 | public bool IsIdle { get; set; } | ||
112 | public bool IsShuttingDown { get; set; } | ||
113 | public int MaxThreads { get; set; } | ||
114 | public int MinThreads { get; set; } | ||
115 | public int InUseThreads { get; set; } | ||
116 | public int ActiveThreads { get; set; } | ||
117 | public int WaitingCallbacks { get; set; } | ||
118 | public int MaxConcurrentWorkItems { get; set; } | ||
119 | } | ||
120 | |||
121 | /// <summary> | ||
92 | /// Miscellaneous utility functions | 122 | /// Miscellaneous utility functions |
93 | /// </summary> | 123 | /// </summary> |
94 | public class Util | 124 | public static class Util |
95 | { | 125 | { |
96 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 126 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
97 | 127 | ||
@@ -109,7 +139,7 @@ namespace OpenSim.Framework | |||
109 | private static SmartThreadPool m_ThreadPool; | 139 | private static SmartThreadPool m_ThreadPool; |
110 | 140 | ||
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. | 141 | // 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 = | 142 | 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(); | 143 | DateTime.ParseExact("1970-01-01 00:00:00 +0", "yyyy-MM-dd hh:mm:ss z", DateTimeFormatInfo.InvariantInfo).ToUniversalTime(); |
114 | 144 | ||
115 | private static readonly string rawUUIDPattern | 145 | private static readonly string rawUUIDPattern |
@@ -120,6 +150,11 @@ namespace OpenSim.Framework | |||
120 | public static FireAndForgetMethod DefaultFireAndForgetMethod = FireAndForgetMethod.SmartThreadPool; | 150 | public static FireAndForgetMethod DefaultFireAndForgetMethod = FireAndForgetMethod.SmartThreadPool; |
121 | public static FireAndForgetMethod FireAndForgetMethod = DefaultFireAndForgetMethod; | 151 | public static FireAndForgetMethod FireAndForgetMethod = DefaultFireAndForgetMethod; |
122 | 152 | ||
153 | public static bool IsPlatformMono | ||
154 | { | ||
155 | get { return Type.GetType("Mono.Runtime") != null; } | ||
156 | } | ||
157 | |||
123 | /// <summary> | 158 | /// <summary> |
124 | /// Gets the name of the directory where the current running executable | 159 | /// Gets the name of the directory where the current running executable |
125 | /// is located | 160 | /// is located |
@@ -217,14 +252,12 @@ namespace OpenSim.Framework | |||
217 | /// </summary> | 252 | /// </summary> |
218 | /// <param name="a">A 3d vector</param> | 253 | /// <param name="a">A 3d vector</param> |
219 | /// <returns>A new vector which is normalized form of the vector</returns> | 254 | /// <returns>A new vector which is normalized form of the vector</returns> |
220 | /// <remarks>The vector paramater cannot be <0,0,0></remarks> | 255 | |
221 | public static Vector3 GetNormalizedVector(Vector3 a) | 256 | public static Vector3 GetNormalizedVector(Vector3 a) |
222 | { | 257 | { |
223 | if (IsZeroVector(a)) | 258 | Vector3 v = new Vector3(a.X, a.Y, a.Z); |
224 | throw new ArgumentException("Vector paramater cannot be a zero vector."); | 259 | v.Normalize(); |
225 | 260 | return v; | |
226 | float Mag = (float) GetMagnitude(a); | ||
227 | return new Vector3(a.X / Mag, a.Y / Mag, a.Z / Mag); | ||
228 | } | 261 | } |
229 | 262 | ||
230 | /// <summary> | 263 | /// <summary> |
@@ -307,6 +340,49 @@ namespace OpenSim.Framework | |||
307 | return Utils.UIntsToLong(X, Y); | 340 | return Utils.UIntsToLong(X, Y); |
308 | } | 341 | } |
309 | 342 | ||
343 | // Regions are identified with a 'handle' made up of its region coordinates packed into a ulong. | ||
344 | // Several places rely on the ability to extract a region's location from its handle. | ||
345 | // Note the location is in 'world coordinates' (see below). | ||
346 | // Region handles are based on the lowest coordinate of the region so trim the passed x,y to be the regions 0,0. | ||
347 | public static ulong RegionWorldLocToHandle(uint X, uint Y) | ||
348 | { | ||
349 | return Utils.UIntsToLong(X, Y); | ||
350 | } | ||
351 | |||
352 | public static ulong RegionLocToHandle(uint X, uint Y) | ||
353 | { | ||
354 | return Utils.UIntsToLong(Util.RegionToWorldLoc(X), Util.RegionToWorldLoc(Y)); | ||
355 | } | ||
356 | |||
357 | public static void RegionHandleToWorldLoc(ulong handle, out uint X, out uint Y) | ||
358 | { | ||
359 | X = (uint)(handle >> 32); | ||
360 | Y = (uint)(handle & (ulong)uint.MaxValue); | ||
361 | } | ||
362 | |||
363 | public static void RegionHandleToRegionLoc(ulong handle, out uint X, out uint Y) | ||
364 | { | ||
365 | uint worldX, worldY; | ||
366 | RegionHandleToWorldLoc(handle, out worldX, out worldY); | ||
367 | X = WorldToRegionLoc(worldX); | ||
368 | Y = WorldToRegionLoc(worldY); | ||
369 | } | ||
370 | |||
371 | // A region location can be 'world coordinates' (meters from zero) or 'region coordinates' | ||
372 | // (number of regions from zero). This measurement of regions relies on the legacy 256 region size. | ||
373 | // These routines exist to make what is being converted explicit so the next person knows what was meant. | ||
374 | // Convert a region's 'world coordinate' to its 'region coordinate'. | ||
375 | public static uint WorldToRegionLoc(uint worldCoord) | ||
376 | { | ||
377 | return worldCoord / Constants.RegionSize; | ||
378 | } | ||
379 | |||
380 | // Convert a region's 'region coordinate' to its 'world coordinate'. | ||
381 | public static uint RegionToWorldLoc(uint regionCoord) | ||
382 | { | ||
383 | return regionCoord * Constants.RegionSize; | ||
384 | } | ||
385 | |||
310 | public static T Clamp<T>(T x, T min, T max) | 386 | public static T Clamp<T>(T x, T min, T max) |
311 | where T : IComparable<T> | 387 | where T : IComparable<T> |
312 | { | 388 | { |
@@ -495,20 +571,18 @@ namespace OpenSim.Framework | |||
495 | 571 | ||
496 | public static int ToUnixTime(DateTime stamp) | 572 | public static int ToUnixTime(DateTime stamp) |
497 | { | 573 | { |
498 | TimeSpan t = stamp.ToUniversalTime() - unixEpoch; | 574 | TimeSpan t = stamp.ToUniversalTime() - UnixEpoch; |
499 | return (int) t.TotalSeconds; | 575 | return (int)t.TotalSeconds; |
500 | } | 576 | } |
501 | 577 | ||
502 | public static DateTime ToDateTime(ulong seconds) | 578 | public static DateTime ToDateTime(ulong seconds) |
503 | { | 579 | { |
504 | DateTime epoch = unixEpoch; | 580 | return UnixEpoch.AddSeconds(seconds); |
505 | return epoch.AddSeconds(seconds); | ||
506 | } | 581 | } |
507 | 582 | ||
508 | public static DateTime ToDateTime(int seconds) | 583 | public static DateTime ToDateTime(int seconds) |
509 | { | 584 | { |
510 | DateTime epoch = unixEpoch; | 585 | return UnixEpoch.AddSeconds(seconds); |
511 | return epoch.AddSeconds(seconds); | ||
512 | } | 586 | } |
513 | 587 | ||
514 | /// <summary> | 588 | /// <summary> |
@@ -976,7 +1050,7 @@ namespace OpenSim.Framework | |||
976 | else if (typeof(T) == typeof(Int32)) | 1050 | else if (typeof(T) == typeof(Int32)) |
977 | val = cnf.GetInt(varname, (int)val); | 1051 | val = cnf.GetInt(varname, (int)val); |
978 | else if (typeof(T) == typeof(float)) | 1052 | else if (typeof(T) == typeof(float)) |
979 | val = cnf.GetFloat(varname, (int)val); | 1053 | val = cnf.GetFloat(varname, (float)val); |
980 | else | 1054 | else |
981 | m_log.ErrorFormat("[UTIL]: Unhandled type {0}", typeof(T)); | 1055 | m_log.ErrorFormat("[UTIL]: Unhandled type {0}", typeof(T)); |
982 | } | 1056 | } |
@@ -1233,7 +1307,7 @@ namespace OpenSim.Framework | |||
1233 | byte[] bytes = | 1307 | byte[] bytes = |
1234 | { | 1308 | { |
1235 | (byte)regionHandle, (byte)(regionHandle >> 8), (byte)(regionHandle >> 16), (byte)(regionHandle >> 24), | 1309 | (byte)regionHandle, (byte)(regionHandle >> 8), (byte)(regionHandle >> 16), (byte)(regionHandle >> 24), |
1236 | (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle << 56), | 1310 | (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle >> 56), |
1237 | (byte)x, (byte)(x >> 8), 0, 0, | 1311 | (byte)x, (byte)(x >> 8), 0, 0, |
1238 | (byte)y, (byte)(y >> 8), 0, 0 }; | 1312 | (byte)y, (byte)(y >> 8), 0, 0 }; |
1239 | return new UUID(bytes, 0); | 1313 | return new UUID(bytes, 0); |
@@ -1244,7 +1318,7 @@ namespace OpenSim.Framework | |||
1244 | byte[] bytes = | 1318 | byte[] bytes = |
1245 | { | 1319 | { |
1246 | (byte)regionHandle, (byte)(regionHandle >> 8), (byte)(regionHandle >> 16), (byte)(regionHandle >> 24), | 1320 | (byte)regionHandle, (byte)(regionHandle >> 8), (byte)(regionHandle >> 16), (byte)(regionHandle >> 24), |
1247 | (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle << 56), | 1321 | (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle >> 56), |
1248 | (byte)x, (byte)(x >> 8), (byte)z, (byte)(z >> 8), | 1322 | (byte)x, (byte)(x >> 8), (byte)z, (byte)(z >> 8), |
1249 | (byte)y, (byte)(y >> 8), 0, 0 }; | 1323 | (byte)y, (byte)(y >> 8), 0, 0 }; |
1250 | return new UUID(bytes, 0); | 1324 | return new UUID(bytes, 0); |
@@ -1317,7 +1391,7 @@ namespace OpenSim.Framework | |||
1317 | ru = "OSX/Mono"; | 1391 | ru = "OSX/Mono"; |
1318 | else | 1392 | else |
1319 | { | 1393 | { |
1320 | if (Type.GetType("Mono.Runtime") != null) | 1394 | if (IsPlatformMono) |
1321 | ru = "Win/Mono"; | 1395 | ru = "Win/Mono"; |
1322 | else | 1396 | else |
1323 | ru = "Win/.NET"; | 1397 | ru = "Win/.NET"; |
@@ -1765,10 +1839,12 @@ namespace OpenSim.Framework | |||
1765 | FireAndForget(callback, null); | 1839 | FireAndForget(callback, null); |
1766 | } | 1840 | } |
1767 | 1841 | ||
1768 | public static void InitThreadPool(int maxThreads) | 1842 | public static void InitThreadPool(int minThreads, int maxThreads) |
1769 | { | 1843 | { |
1770 | if (maxThreads < 2) | 1844 | if (maxThreads < 2) |
1771 | throw new ArgumentOutOfRangeException("maxThreads", "maxThreads must be greater than 2"); | 1845 | throw new ArgumentOutOfRangeException("maxThreads", "maxThreads must be greater than 2"); |
1846 | if (minThreads > maxThreads || minThreads < 2) | ||
1847 | throw new ArgumentOutOfRangeException("minThreads", "minThreads must be greater than 2 and less than or equal to maxThreads"); | ||
1772 | if (m_ThreadPool != null) | 1848 | if (m_ThreadPool != null) |
1773 | throw new InvalidOperationException("SmartThreadPool is already initialized"); | 1849 | throw new InvalidOperationException("SmartThreadPool is already initialized"); |
1774 | 1850 | ||
@@ -1776,7 +1852,7 @@ namespace OpenSim.Framework | |||
1776 | startInfo.ThreadPoolName = "Util"; | 1852 | startInfo.ThreadPoolName = "Util"; |
1777 | startInfo.IdleTimeout = 2000; | 1853 | startInfo.IdleTimeout = 2000; |
1778 | startInfo.MaxWorkerThreads = maxThreads; | 1854 | startInfo.MaxWorkerThreads = maxThreads; |
1779 | startInfo.MinWorkerThreads = 2; | 1855 | startInfo.MinWorkerThreads = minThreads; |
1780 | 1856 | ||
1781 | m_ThreadPool = new SmartThreadPool(startInfo); | 1857 | m_ThreadPool = new SmartThreadPool(startInfo); |
1782 | } | 1858 | } |
@@ -1851,8 +1927,8 @@ namespace OpenSim.Framework | |||
1851 | break; | 1927 | break; |
1852 | case FireAndForgetMethod.SmartThreadPool: | 1928 | case FireAndForgetMethod.SmartThreadPool: |
1853 | if (m_ThreadPool == null) | 1929 | if (m_ThreadPool == null) |
1854 | InitThreadPool(15); | 1930 | InitThreadPool(2, 15); |
1855 | m_ThreadPool.QueueWorkItem(SmartThreadPoolCallback, new object[] { realCallback, obj }); | 1931 | m_ThreadPool.QueueWorkItem((cb, o) => cb(o), realCallback, obj); |
1856 | break; | 1932 | break; |
1857 | case FireAndForgetMethod.Thread: | 1933 | case FireAndForgetMethod.Thread: |
1858 | Thread thread = new Thread(delegate(object o) { realCallback(o); }); | 1934 | Thread thread = new Thread(delegate(object o) { realCallback(o); }); |
@@ -1864,72 +1940,29 @@ namespace OpenSim.Framework | |||
1864 | } | 1940 | } |
1865 | 1941 | ||
1866 | /// <summary> | 1942 | /// <summary> |
1867 | /// Get a thread pool report. | 1943 | /// Get information about the current state of the smart thread pool. |
1868 | /// </summary> | 1944 | /// </summary> |
1869 | /// <returns></returns> | 1945 | /// <returns> |
1870 | public static string GetThreadPoolReport() | 1946 | /// null if this isn't the pool being used for non-scriptengine threads. |
1947 | /// </returns> | ||
1948 | public static STPInfo GetSmartThreadPoolInfo() | ||
1871 | { | 1949 | { |
1872 | string threadPoolUsed = null; | 1950 | if (m_ThreadPool == null) |
1873 | int maxThreads = 0; | 1951 | 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 | 1952 | ||
1922 | return sb.ToString(); | 1953 | STPInfo stpi = new STPInfo(); |
1923 | } | 1954 | stpi.Name = m_ThreadPool.Name; |
1955 | stpi.STPStartInfo = m_ThreadPool.STPStartInfo; | ||
1956 | stpi.IsIdle = m_ThreadPool.IsIdle; | ||
1957 | stpi.IsShuttingDown = m_ThreadPool.IsShuttingdown; | ||
1958 | stpi.MaxThreads = m_ThreadPool.MaxThreads; | ||
1959 | stpi.MinThreads = m_ThreadPool.MinThreads; | ||
1960 | stpi.InUseThreads = m_ThreadPool.InUseThreads; | ||
1961 | stpi.ActiveThreads = m_ThreadPool.ActiveThreads; | ||
1962 | stpi.WaitingCallbacks = m_ThreadPool.WaitingCallbacks; | ||
1963 | stpi.MaxConcurrentWorkItems = m_ThreadPool.Concurrency; | ||
1924 | 1964 | ||
1925 | private static object SmartThreadPoolCallback(object o) | 1965 | return stpi; |
1926 | { | ||
1927 | object[] array = (object[])o; | ||
1928 | WaitCallback callback = (WaitCallback)array[0]; | ||
1929 | object obj = array[1]; | ||
1930 | |||
1931 | callback(obj); | ||
1932 | return null; | ||
1933 | } | 1966 | } |
1934 | 1967 | ||
1935 | #endregion FireAndForget Threading Pattern | 1968 | #endregion FireAndForget Threading Pattern |
@@ -2058,8 +2091,10 @@ namespace OpenSim.Framework | |||
2058 | #region Xml Serialization Utilities | 2091 | #region Xml Serialization Utilities |
2059 | public static bool ReadBoolean(XmlTextReader reader) | 2092 | public static bool ReadBoolean(XmlTextReader reader) |
2060 | { | 2093 | { |
2094 | // AuroraSim uses "int" for some fields that are boolean in OpenSim, e.g. "PassCollisions". Don't fail because of this. | ||
2061 | reader.ReadStartElement(); | 2095 | reader.ReadStartElement(); |
2062 | bool result = Boolean.Parse(reader.ReadContentAsString().ToLower()); | 2096 | string val = reader.ReadContentAsString().ToLower(); |
2097 | bool result = val.Equals("true") || val.Equals("1"); | ||
2063 | reader.ReadEndElement(); | 2098 | reader.ReadEndElement(); |
2064 | 2099 | ||
2065 | return result; | 2100 | return result; |
@@ -2148,7 +2183,7 @@ namespace OpenSim.Framework | |||
2148 | /// <param name="secret">the secret part</param> | 2183 | /// <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) | 2184 | public static bool ParseUniversalUserIdentifier(string value, out UUID uuid, out string url, out string firstname, out string lastname, out string secret) |
2150 | { | 2185 | { |
2151 | uuid = UUID.Zero; url = string.Empty; firstname = "Unknown"; lastname = "User"; secret = string.Empty; | 2186 | uuid = UUID.Zero; url = string.Empty; firstname = "Unknown"; lastname = "UserUPUUI"; secret = string.Empty; |
2152 | 2187 | ||
2153 | string[] parts = value.Split(';'); | 2188 | string[] parts = value.Split(';'); |
2154 | if (parts.Length >= 1) | 2189 | if (parts.Length >= 1) |
@@ -2282,7 +2317,7 @@ namespace OpenSim.Framework | |||
2282 | { | 2317 | { |
2283 | lock (m_syncRoot) | 2318 | lock (m_syncRoot) |
2284 | { | 2319 | { |
2285 | m_lowQueue.Enqueue(data); | 2320 | q.Enqueue(data); |
2286 | m_s.WaitOne(0); | 2321 | m_s.WaitOne(0); |
2287 | m_s.Release(); | 2322 | m_s.Release(); |
2288 | } | 2323 | } |
@@ -2322,7 +2357,7 @@ namespace OpenSim.Framework | |||
2322 | { | 2357 | { |
2323 | if (m_highQueue.Count > 0) | 2358 | if (m_highQueue.Count > 0) |
2324 | res = m_highQueue.Dequeue(); | 2359 | res = m_highQueue.Dequeue(); |
2325 | else | 2360 | else if (m_lowQueue.Count > 0) |
2326 | res = m_lowQueue.Dequeue(); | 2361 | res = m_lowQueue.Dequeue(); |
2327 | 2362 | ||
2328 | if (m_highQueue.Count == 0 && m_lowQueue.Count == 0) | 2363 | if (m_highQueue.Count == 0 && m_lowQueue.Count == 0) |