// 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
public static void Close ()
{
- lock (lock_) {
+ lock (ListenersSyncRoot) {
foreach (TraceListener listener in Listeners) {
listener.Close ();
}
[MonoTODO]
public static void Fail (string message)
{
- lock (lock_) {
+ lock (ListenersSyncRoot) {
foreach (TraceListener listener in Listeners) {
listener.Fail (message);
}
[MonoTODO]
public static void Fail (string message, string detailMessage)
{
- lock (lock_) {
+ lock (ListenersSyncRoot) {
foreach (TraceListener listener in Listeners) {
listener.Fail (message, detailMessage);
}
public static void Flush ()
{
- lock (lock_) {
+ lock (ListenersSyncRoot) {
foreach (TraceListener listener in Listeners){
listener.Flush ();
}
public static void Indent ()
{
- lock (lock_) {
+ lock (ListenersSyncRoot) {
foreach (TraceListener listener in Listeners) {
-Console.WriteLine("before incr. listener.IndentLevel={0}", listener.IndentLevel);
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--;
}
}
public static void Write (object value)
{
- lock (lock_) {
+ lock (ListenersSyncRoot) {
foreach (TraceListener listener in Listeners) {
listener.Write (value);
public static void Write (string message)
{
- lock (lock_) {
+ lock (ListenersSyncRoot) {
foreach (TraceListener listener in Listeners) {
listener.Write (message);
public static void Write (object value, string category)
{
- lock (lock_) {
+ lock (ListenersSyncRoot) {
foreach (TraceListener listener in Listeners) {
listener.Write (value, category);
public static void Write (string message, string category)
{
- lock (lock_) {
+ lock (ListenersSyncRoot) {
foreach (TraceListener listener in Listeners) {
listener.Write (message, category);
public static void WriteLine (object value)
{
- lock (lock_) {
+ lock (ListenersSyncRoot) {
foreach (TraceListener listener in Listeners) {
listener.WriteLine (value);
public static void WriteLine (string message)
{
- lock (lock_) {
+ lock (ListenersSyncRoot) {
foreach (TraceListener listener in Listeners) {
listener.WriteLine (message);
public static void WriteLine (object value, string category)
{
- lock (lock_) {
+ lock (ListenersSyncRoot) {
foreach (TraceListener listener in Listeners) {
listener.WriteLine (value, category);
public static void WriteLine (string message, string category)
{
- lock (lock_) {
+ lock (ListenersSyncRoot) {
foreach (TraceListener listener in Listeners) {
listener.WriteLine (message, category);