New test.
[mono.git] / mcs / class / System / System.Diagnostics / TraceImpl.cs
index 8f135a8097873763900905ac8a17777c8124a88e..cc66f12d304a778b0a752f8c72fcf1c4fe927d43 100644 (file)
 // Authors:
 //   Jonathan Pryor (jonpryor@vt.edu)
 //
-// (C) 2002 Jonathan Pryor
+// (C) 2002, 2005 Jonathan Pryor
+//
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
 
 
 using System;
+using System.Collections;
 using System.Diagnostics;
+using System.Configuration;
+using System.Threading;
 
 namespace System.Diagnostics {
 
        internal class TraceImpl {
 
+#if NO_LOCK_FREE
                private static object lock_ = new object ();
+#endif
+
+               private static bool autoFlush;
+
+               [ThreadStatic]
+               private static int indentLevel = 0;
+
+               [ThreadStatic]
+               private static int indentSize;
 
-               private static bool autoFlush = false;
+               static TraceImpl ()
+               {
+                       // defaults
+                       autoFlush = false;
+                       indentLevel = 0;
+                       indentSize = 4;
+               }
+
+               private TraceImpl ()
+               {
+               }
 
                public static bool AutoFlush {
                        get {return autoFlush;}
                        set {autoFlush = value;}
                }
 
-               [ThreadStatic]
-               private static int indentLevel = 0;
-
                public static int IndentLevel {
                        get {return indentLevel;}
                        set {
-                               indentLevel = value;
+                               lock (ListenersSyncRoot) {
+                                       indentLevel = value;
 
-                               // Don't need to lock for threadsafety as 
-                               // TraceListener.IndentLevel is [ThreadStatic]
-                               foreach (TraceListener t in Listeners) {
-                                       t.IndentLevel = indentLevel;
+                                       foreach (TraceListener t in Listeners) {
+                                               t.IndentLevel = indentLevel;
+                                       }
                                }
                        }
                }
 
-               [ThreadStatic]
-               private static int indentSize = 4;
-
                public static int IndentSize {
                        get {return indentSize;}
                        set {
-                               indentSize = value;
+                               lock (ListenersSyncRoot) {
+                                       indentSize = value;
 
-                               // Don't need to lock for threadsafety as 
-                               // TraceListener.IndentSize is [ThreadStatic]
-                               foreach (TraceListener t in Listeners) {
-                                       t.IndentSize = indentSize;
+                                       foreach (TraceListener t in Listeners) {
+                                               t.IndentSize = indentSize;
+                                       }
                                }
                        }
                }
 
-               private static TraceListenerCollection listeners = 
-                       new TraceListenerCollection ();
+               private static object listeners;
 
                public static TraceListenerCollection Listeners {
-                       get {return listeners;}
+                       get {
+                               InitOnce ();
+
+                               return (TraceListenerCollection) listeners;
+                       }
+               }
+
+               private static object ListenersSyncRoot {
+                       get {
+                               return ((ICollection) Listeners).SyncRoot;
+                       }
+               }
+
+               // Initialize the world.
+               //
+               // This logically belongs in the static constructor (as it only needs
+               // to be done once), except for one thing: if the .config file has a
+               // syntax error, .NET throws a ConfigurationException.  If we read the
+               // .config file in the static ctor, we throw a ConfigurationException
+               // from the static ctor, which results in a TypeLoadException.  Oops.
+               // Reading the .config file here will allow the static ctor to
+               // complete successfully, allowing us to throw a normal
+               // ConfigurationException should the .config file contain an error.
+               //
+               // There are also some ordering issues.
+               //
+               // The DiagnosticsConfigurationHandler assumes that the TraceImpl.Listeners
+               // collection exists (so it can initialize the DefaultTraceListener and
+               // add/remove existing listeners).
+               private static object InitOnce ()
+               {
+                       object d = null;
+#if !NO_LOCK_FREE
+                       // The lock-free version
+                       if (listeners == null) {
+                               TraceListenerCollection c = new TraceListenerCollection ();
+                               Thread.MemoryBarrier ();
+                               while (Interlocked.CompareExchange (ref listeners, c, null) == null) {
+                                       // Read in the .config file and get the ball rolling...
+                                       d = DiagnosticsConfiguration.Settings;
+                               }
+                               Thread.MemoryBarrier ();
+                       }
+#else
+                       // The lock version (saved for posterity and potential debugging)
+                       lock (lock_) {
+                               if (listeners == null) {
+                                       listeners = new TraceListenerCollection ();
+                                       // Read in the .config file and get the ball rolling...
+                                       d = DiagnosticsConfiguration.Settings;
+                               }
+                       }
+#endif
+                       return d;
                }
 
                // FIXME: According to MSDN, this method should display a dialog box
@@ -90,7 +180,7 @@ namespace System.Diagnostics {
 
                public static void Close ()
                {
-                       lock (lock_) {
+                       lock (ListenersSyncRoot) {
                                foreach (TraceListener listener in Listeners) {
                                        listener.Close ();
                                }
@@ -101,7 +191,7 @@ namespace System.Diagnostics {
                [MonoTODO]
                public static void Fail (string message)
                {
-                       lock (lock_) {
+                       lock (ListenersSyncRoot) {
                                foreach (TraceListener listener in Listeners) {
                                        listener.Fail (message);
                                }
@@ -112,7 +202,7 @@ namespace System.Diagnostics {
                [MonoTODO]
                public static void Fail (string message, string detailMessage)
                {
-                       lock (lock_) {
+                       lock (ListenersSyncRoot) {
                                foreach (TraceListener listener in Listeners) {
                                        listener.Fail (message, detailMessage);
                                }
@@ -121,7 +211,7 @@ namespace System.Diagnostics {
 
                public static void Flush ()
                {
-                       lock (lock_) {
+                       lock (ListenersSyncRoot) {
                                foreach (TraceListener listener in Listeners){
                                        listener.Flush ();
                                }
@@ -130,9 +220,8 @@ namespace System.Diagnostics {
 
                public static void Indent ()
                {
-                       lock (lock_) {
+                       lock (ListenersSyncRoot) {
                                foreach (TraceListener listener in Listeners) {
-Console.WriteLine("before incr. listener.IndentLevel={0}", listener.IndentLevel);
                                        listener.IndentLevel++;
                                }
                        }
@@ -140,9 +229,8 @@ Console.WriteLine("before incr. listener.IndentLevel={0}", listener.IndentLevel)
 
                public static void Unindent ()
                {
-                       lock (lock_) {
+                       lock (ListenersSyncRoot) {
                                foreach (TraceListener listener in Listeners) {
-Console.WriteLine("before decr. listener.IndentLevel={0}", listener.IndentLevel);
                                        listener.IndentLevel--;
                                }
                        }
@@ -150,7 +238,7 @@ Console.WriteLine("before decr. listener.IndentLevel={0}", listener.IndentLevel)
 
                public static void Write (object value)
                {
-                       lock (lock_) {
+                       lock (ListenersSyncRoot) {
                                foreach (TraceListener listener in Listeners) {
                                        listener.Write (value);
 
@@ -162,7 +250,7 @@ Console.WriteLine("before decr. listener.IndentLevel={0}", listener.IndentLevel)
 
                public static void Write (string message)
                {
-                       lock (lock_) {
+                       lock (ListenersSyncRoot) {
                                foreach (TraceListener listener in Listeners) {
                                        listener.Write (message);
 
@@ -174,7 +262,7 @@ Console.WriteLine("before decr. listener.IndentLevel={0}", listener.IndentLevel)
 
                public static void Write (object value, string category)
                {
-                       lock (lock_) {
+                       lock (ListenersSyncRoot) {
                                foreach (TraceListener listener in Listeners) {
                                        listener.Write (value, category);
 
@@ -186,7 +274,7 @@ Console.WriteLine("before decr. listener.IndentLevel={0}", listener.IndentLevel)
 
                public static void Write (string message, string category)
                {
-                       lock (lock_) {
+                       lock (ListenersSyncRoot) {
                                foreach (TraceListener listener in Listeners) {
                                        listener.Write (message, category);
 
@@ -224,7 +312,7 @@ Console.WriteLine("before decr. listener.IndentLevel={0}", listener.IndentLevel)
 
                public static void WriteLine (object value)
                {
-                       lock (lock_) {
+                       lock (ListenersSyncRoot) {
                                foreach (TraceListener listener in Listeners) {
                                        listener.WriteLine (value);
 
@@ -236,7 +324,7 @@ Console.WriteLine("before decr. listener.IndentLevel={0}", listener.IndentLevel)
 
                public static void WriteLine (string message)
                {
-                       lock (lock_) {
+                       lock (ListenersSyncRoot) {
                                foreach (TraceListener listener in Listeners) {
                                        listener.WriteLine (message);
 
@@ -248,7 +336,7 @@ Console.WriteLine("before decr. listener.IndentLevel={0}", listener.IndentLevel)
 
                public static void WriteLine (object value, string category)
                {
-                       lock (lock_) {
+                       lock (ListenersSyncRoot) {
                                foreach (TraceListener listener in Listeners) {
                                        listener.WriteLine (value, category);
 
@@ -260,7 +348,7 @@ Console.WriteLine("before decr. listener.IndentLevel={0}", listener.IndentLevel)
 
                public static void WriteLine (string message, string category)
                {
-                       lock (lock_) {
+                       lock (ListenersSyncRoot) {
                                foreach (TraceListener listener in Listeners) {
                                        listener.WriteLine (message, category);