aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--OpenSim/Framework/Util.cs143
1 files changed, 114 insertions, 29 deletions
diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs
index c2c9698..ed94c6f 100644
--- a/OpenSim/Framework/Util.cs
+++ b/OpenSim/Framework/Util.cs
@@ -116,6 +116,16 @@ namespace OpenSim.Framework
116 { 116 {
117 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 117 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
118 118
119 /// <summary>
120 /// Log every invocation of a thread using the threadpool.
121 /// </summary>
122 public static bool LogThreadPool { get; set; }
123
124 static Util()
125 {
126 LogThreadPool = false;
127 }
128
119 private static uint nextXferID = 5000; 129 private static uint nextXferID = 5000;
120 private static Random randomClass = new Random(); 130 private static Random randomClass = new Random();
121 131
@@ -1887,10 +1897,17 @@ namespace OpenSim.Framework
1887 } 1897 }
1888 } 1898 }
1889 1899
1900
1901 private static long nextThreadFuncNum = 0;
1902 private static long numQueuedThreadFuncs = 0;
1903 private static long numRunningThreadFuncs = 0;
1904
1890 public static void FireAndForget(System.Threading.WaitCallback callback, object obj) 1905 public static void FireAndForget(System.Threading.WaitCallback callback, object obj)
1891 { 1906 {
1892 WaitCallback realCallback; 1907 WaitCallback realCallback;
1893 1908
1909 long threadFuncNum = Interlocked.Increment(ref nextThreadFuncNum);
1910
1894 if (FireAndForgetMethod == FireAndForgetMethod.RegressionTest) 1911 if (FireAndForgetMethod == FireAndForgetMethod.RegressionTest)
1895 { 1912 {
1896 // If we're running regression tests, then we want any exceptions to rise up to the test code. 1913 // If we're running regression tests, then we want any exceptions to rise up to the test code.
@@ -1903,49 +1920,117 @@ namespace OpenSim.Framework
1903 // for decimals places but is read by a culture that treats commas as number seperators. 1920 // for decimals places but is read by a culture that treats commas as number seperators.
1904 realCallback = o => 1921 realCallback = o =>
1905 { 1922 {
1906 Culture.SetCurrentCulture(); 1923 long numQueued1 = Interlocked.Decrement(ref numQueuedThreadFuncs);
1924 long numRunning1 = Interlocked.Increment(ref numRunningThreadFuncs);
1907 1925
1908 try 1926 try
1909 { 1927 {
1928 if (LogThreadPool)
1929 m_log.DebugFormat("Run threadfunc {0} (Queued {1}, Running {2})", threadFuncNum, numQueued1, numRunning1);
1930
1931 Culture.SetCurrentCulture();
1932
1910 callback(o); 1933 callback(o);
1911 } 1934 }
1912 catch (Exception e) 1935 catch (Exception e)
1913 { 1936 {
1914 m_log.ErrorFormat( 1937 m_log.Error("[UTIL]: FireAndForget thread terminated with error ", e);
1915 "[UTIL]: Continuing after async_call_method thread terminated with exception {0}{1}", 1938 }
1916 e.Message, e.StackTrace); 1939 finally
1940 {
1941 Interlocked.Decrement(ref numRunningThreadFuncs);
1942 if (LogThreadPool)
1943 m_log.Debug("Exit threadfunc " + threadFuncNum);
1917 } 1944 }
1918 }; 1945 };
1919 } 1946 }
1920 1947
1921 switch (FireAndForgetMethod) 1948 long numQueued = Interlocked.Increment(ref numQueuedThreadFuncs);
1949 try
1922 { 1950 {
1923 case FireAndForgetMethod.RegressionTest: 1951 if (LogThreadPool)
1924 case FireAndForgetMethod.None: 1952 m_log.DebugFormat("Queue threadfunc {0} (Queued {1}, Running {2}) {3}",
1925 realCallback.Invoke(obj); 1953 threadFuncNum, numQueued, numRunningThreadFuncs, GetFireAndForgetStackTrace(true));
1926 break; 1954
1927 case FireAndForgetMethod.UnsafeQueueUserWorkItem: 1955 switch (FireAndForgetMethod)
1928 ThreadPool.UnsafeQueueUserWorkItem(realCallback, obj); 1956 {
1929 break; 1957 case FireAndForgetMethod.RegressionTest:
1930 case FireAndForgetMethod.QueueUserWorkItem: 1958 case FireAndForgetMethod.None:
1931 ThreadPool.QueueUserWorkItem(realCallback, obj); 1959 realCallback.Invoke(obj);
1932 break; 1960 break;
1933 case FireAndForgetMethod.BeginInvoke: 1961 case FireAndForgetMethod.UnsafeQueueUserWorkItem:
1934 FireAndForgetWrapper wrapper = FireAndForgetWrapper.Instance; 1962 ThreadPool.UnsafeQueueUserWorkItem(realCallback, obj);
1935 wrapper.FireAndForget(realCallback, obj); 1963 break;
1936 break; 1964 case FireAndForgetMethod.QueueUserWorkItem:
1937 case FireAndForgetMethod.SmartThreadPool: 1965 ThreadPool.QueueUserWorkItem(realCallback, obj);
1938 if (m_ThreadPool == null) 1966 break;
1939 InitThreadPool(2, 15); 1967 case FireAndForgetMethod.BeginInvoke:
1940 m_ThreadPool.QueueWorkItem((cb, o) => cb(o), realCallback, obj); 1968 FireAndForgetWrapper wrapper = FireAndForgetWrapper.Instance;
1941 break; 1969 wrapper.FireAndForget(realCallback, obj);
1942 case FireAndForgetMethod.Thread: 1970 break;
1943 Thread thread = new Thread(delegate(object o) { realCallback(o); }); 1971 case FireAndForgetMethod.SmartThreadPool:
1944 thread.Start(obj); 1972 if (m_ThreadPool == null)
1973 InitThreadPool(2, 15);
1974 m_ThreadPool.QueueWorkItem((cb, o) => cb(o), realCallback, obj);
1975 break;
1976 case FireAndForgetMethod.Thread:
1977 Thread thread = new Thread(delegate(object o) { realCallback(o); });
1978 thread.Start(obj);
1979 break;
1980 default:
1981 throw new NotImplementedException();
1982 }
1983 }
1984 catch (Exception)
1985 {
1986 Interlocked.Decrement(ref numQueuedThreadFuncs);
1987 throw;
1988 }
1989 }
1990
1991 /// <summary>
1992 /// Returns a stack trace for a thread added using FireAndForget().
1993 /// </summary>
1994 /// <param name="full">True: return full stack trace; False: return only the first frame</param>
1995 private static string GetFireAndForgetStackTrace(bool full)
1996 {
1997 string src = Environment.StackTrace;
1998 string[] lines = src.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
1999
2000 StringBuilder dest = new StringBuilder(src.Length);
2001
2002 bool started = false;
2003 bool first = true;
2004
2005 for (int i = 0; i < lines.Length; i++)
2006 {
2007 string line = lines[i];
2008
2009 if (!started)
2010 {
2011 // Skip the initial stack frames, because they're of no interest for debugging
2012 if (line.Contains("StackTrace") || line.Contains("FireAndForget"))
2013 continue;
2014 started = true;
2015 }
2016
2017 if (first)
2018 {
2019 line = line.TrimStart();
2020 first = false;
2021 }
2022
2023 bool last = (i == lines.Length - 1) || !full;
2024 if (last)
2025 dest.Append(line);
2026 else
2027 dest.AppendLine(line);
2028
2029 if (!full)
1945 break; 2030 break;
1946 default:
1947 throw new NotImplementedException();
1948 } 2031 }
2032
2033 return dest.ToString();
1949 } 2034 }
1950 2035
1951 /// <summary> 2036 /// <summary>