1 //------------------------------------------------------------------------------
2 // <copyright file="_LoggingObject.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 //------------------------------------------------------------------------------
8 // We have function based stack and thread based logging of basic behavior. We
9 // also now have the ability to run a "watch thread" which does basic hang detection
10 // and error-event based logging. The logging code buffers the callstack/picture
11 // of all COMNET threads, and upon error from an assert or a hang, it will open a file
12 // and dump the snapsnot. Future work will allow this to be configed by registry and
13 // to use Runtime based logging. We'd also like to have different levels of logging.
16 namespace System.Net {
17 using System.Collections;
18 using System.Collections.Generic;
20 using System.Threading;
21 using System.Diagnostics;
22 using System.Security.Permissions;
23 using System.Security.Principal;
24 using System.Security;
25 using Microsoft.Win32;
26 using System.Runtime.ConstrainedExecution;
27 using System.Globalization;
28 using System.Configuration;
31 // BaseLoggingObject - used to disable logging,
32 // this is just a base class that does nothing.
35 internal class BaseLoggingObject {
37 internal BaseLoggingObject() {
40 internal virtual void EnterFunc(string funcname) {
43 internal virtual void LeaveFunc(string funcname) {
46 internal virtual void DumpArrayToConsole() {
49 internal virtual void PrintLine(string msg) {
52 internal virtual void DumpArray(bool shouldClose) {
55 internal virtual void DumpArrayToFile(bool shouldClose) {
58 internal virtual void Flush() {
61 internal virtual void Flush(bool close) {
64 internal virtual void LoggingMonitorTick() {
67 internal virtual void Dump(byte[] buffer) {
70 internal virtual void Dump(byte[] buffer, int length) {
73 internal virtual void Dump(byte[] buffer, int offset, int length) {
76 internal virtual void Dump(IntPtr pBuffer, int offset, int length) {
79 } // class BaseLoggingObject
85 internal class LoggingObject : BaseLoggingObject {
86 public ArrayList _Logarray;
87 private Hashtable _ThreadNesting;
88 private int _AddCount;
89 private StreamWriter _Stream;
90 private int _IamAlive;
91 private int _LastIamAlive;
92 private bool _Finalized = false;
93 private double _NanosecondsPerTick;
94 private int _StartMilliseconds;
95 private long _StartTicks;
97 internal LoggingObject() : base() {
98 _Logarray = new ArrayList();
99 _ThreadNesting = new Hashtable();
104 if (GlobalLog.s_UsePerfCounter) {
106 SafeNativeMethods.QueryPerformanceFrequency(out ticksPerSecond);
107 _NanosecondsPerTick = 10000000.0/(double)ticksPerSecond;
108 SafeNativeMethods.QueryPerformanceCounter(out _StartTicks);
110 _StartMilliseconds = Environment.TickCount;
115 // LoggingMonitorTick - this function is run from the monitor thread,
116 // and used to check to see if there any hangs, ie no logging
120 internal override void LoggingMonitorTick() {
121 if ( _LastIamAlive == _IamAlive ) {
122 PrintLine("================= Error TIMEOUT - HANG DETECTED =================");
125 _LastIamAlive = _IamAlive;
128 internal override void EnterFunc(string funcname) {
133 ValidatePush(funcname);
137 internal override void LeaveFunc(string funcname) {
143 ValidatePop(funcname);
146 internal override void DumpArrayToConsole() {
147 for (int i=0; i < _Logarray.Count; i++) {
148 Console.WriteLine((string) _Logarray[i]);
152 internal override void PrintLine(string msg) {
160 spc = GetNestingString();
162 string tickString = "";
164 if (GlobalLog.s_UsePerfCounter) {
166 SafeNativeMethods.QueryPerformanceCounter(out nowTicks);
167 if (_StartTicks>nowTicks) { // counter reset, restart from 0
168 _StartTicks = nowTicks;
170 nowTicks -= _StartTicks;
171 if (GlobalLog.s_UseTimeSpan) {
172 tickString = new TimeSpan((long)(nowTicks*_NanosecondsPerTick)).ToString();
173 // note: TimeSpan().ToString() doesn't return the uSec part
174 // if its 0. .ToString() returns [H*]HH:MM:SS:uuuuuuu, hence 16
175 if (tickString.Length < 16) {
176 tickString += ".0000000";
180 tickString = ((double)nowTicks*_NanosecondsPerTick/10000).ToString("f3");
184 int nowMilliseconds = Environment.TickCount;
185 if (_StartMilliseconds>nowMilliseconds) {
186 _StartMilliseconds = nowMilliseconds;
188 nowMilliseconds -= _StartMilliseconds;
189 if (GlobalLog.s_UseTimeSpan) {
190 tickString = new TimeSpan(nowMilliseconds*10000).ToString();
191 // note: TimeSpan().ToString() doesn't return the uSec part
192 // if its 0. .ToString() returns [H*]HH:MM:SS:uuuuuuu, hence 16
193 if (tickString.Length < 16) {
194 tickString += ".0000000";
198 tickString = nowMilliseconds.ToString();
204 if (GlobalLog.s_UseThreadId) {
206 object threadData = Thread.GetData(GlobalLog.s_ThreadIdSlot);
207 if (threadData!= null) {
208 threadId = (uint)threadData;
212 catch(Exception exception) {
213 if (exception is ThreadAbortException || exception is StackOverflowException || exception is OutOfMemoryException) {
218 threadId = UnsafeNclNativeMethods.GetCurrentThreadId();
219 Thread.SetData(GlobalLog.s_ThreadIdSlot, threadId);
223 threadId = (uint)Thread.CurrentThread.GetHashCode();
226 string str = "[" + threadId.ToString("x8") + "]" + " (" +tickString+ ") " + spc + msg;
231 int MaxLines = GlobalLog.s_DumpToConsole ? 0 : GlobalLog.MaxLinesBeforeSave;
232 if (_AddCount > MaxLines) {
235 _Logarray = new ArrayList();
240 internal override void DumpArray(bool shouldClose) {
241 if ( GlobalLog.s_DumpToConsole ) {
242 DumpArrayToConsole();
244 DumpArrayToFile(shouldClose);
248 internal unsafe override void Dump(byte[] buffer, int offset, int length) {
249 //if (!GlobalLog.s_DumpWebData) {
256 if (offset > buffer.Length) {
257 PrintLine("(offset out of range)");
260 if (length > GlobalLog.s_MaxDumpSize) {
261 PrintLine("(printing " + GlobalLog.s_MaxDumpSize.ToString() + " out of " + length.ToString() + ")");
262 length = GlobalLog.s_MaxDumpSize;
264 if ((length < 0) || (length > buffer.Length - offset)) {
265 length = buffer.Length - offset;
267 fixed (byte* pBuffer = buffer) {
268 Dump((IntPtr)pBuffer, offset, length);
272 internal unsafe override void Dump(IntPtr pBuffer, int offset, int length) {
273 //if (!GlobalLog.s_DumpWebData) {
276 if (pBuffer==IntPtr.Zero || length<0) {
280 if (length > GlobalLog.s_MaxDumpSize) {
281 PrintLine("(printing " + GlobalLog.s_MaxDumpSize.ToString() + " out of " + length.ToString() + ")");
282 length = GlobalLog.s_MaxDumpSize;
284 byte* buffer = (byte*)pBuffer + offset;
285 Dump(buffer, length);
288 unsafe void Dump(byte* buffer, int length) {
291 int n = Math.Min(length, 16);
292 string disp = ((IntPtr)buffer).ToString("X8") + " : " + offset.ToString("X8") + " : ";
294 for (int i = 0; i < n; ++i) {
295 current = *(buffer + i);
296 disp += current.ToString("X2") + ((i == 7) ? '-' : ' ');
298 for (int i = n; i < 16; ++i) {
302 for (int i = 0; i < n; ++i) {
303 current = *(buffer + i);
304 disp += ((current < 0x20) || (current > 0x7e)) ? '.' : (char)current;
310 } while (length > 0);
313 // SECURITY: This is dev-debugging class and we need some permissions
314 // to use it under trust-restricted environment as well.
315 [PermissionSet(SecurityAction.Assert, Name="FullTrust")]
316 internal override void DumpArrayToFile(bool shouldClose) {
320 string mainLogFileRoot = GlobalLog.s_RootDirectory + "System.Net";
321 string mainLogFile = mainLogFileRoot;
322 for (int k=0; k<20; k++) {
324 mainLogFile = mainLogFileRoot + "." + k.ToString();
326 string fileName = mainLogFile + ".log";
327 if (!File.Exists(fileName)) {
329 _Stream = new StreamWriter(fileName);
332 catch (Exception exception) {
333 if (exception is ThreadAbortException || exception is StackOverflowException || exception is OutOfMemoryException) {
336 if (exception is SecurityException || exception is UnauthorizedAccessException) {
337 // can't be CAS (we assert) this is an ACL issue
344 _Stream = StreamWriter.Null;
346 // write a header with information about the Process and the AppDomain
347 _Stream.Write("# MachineName: " + Environment.MachineName + "\r\n");
348 _Stream.Write("# ProcessName: " + Process.GetCurrentProcess().ProcessName + " (pid: " + Process.GetCurrentProcess().Id + ")\r\n");
349 _Stream.Write("# AppDomainId: " + AppDomain.CurrentDomain.Id + "\r\n");
350 _Stream.Write("# CurrentIdentity: " + WindowsIdentity.GetCurrent().Name + "\r\n");
351 _Stream.Write("# CommandLine: " + Environment.CommandLine + "\r\n");
352 _Stream.Write("# ClrVersion: " + Environment.Version + "\r\n");
353 _Stream.Write("# CreationDate: " + DateTime.Now.ToString("g") + "\r\n");
357 if (_Logarray!=null) {
358 for (int i=0; i<_Logarray.Count; i++) {
359 _Stream.Write((string)_Logarray[i]);
360 _Stream.Write("\r\n");
363 if (_Logarray.Count > 0 && _Stream != null)
367 catch (Exception exception) {
368 if (exception is ThreadAbortException || exception is StackOverflowException || exception is OutOfMemoryException) {
372 if (shouldClose && _Stream!=null) {
376 catch (ObjectDisposedException) { }
382 internal override void Flush() {
386 internal override void Flush(bool close) {
388 if (!GlobalLog.s_DumpToConsole) {
389 DumpArrayToFile(close);
395 private class ThreadInfoData {
396 public ThreadInfoData(string indent) {
398 NestingStack = new Stack();
400 public string Indent;
401 public Stack NestingStack;
404 string IndentString {
407 Object obj = _ThreadNesting[Thread.CurrentThread.GetHashCode()];
408 if (!GlobalLog.s_DebugCallNesting) {
410 _ThreadNesting[Thread.CurrentThread.GetHashCode()] = indent;
412 indent = (String) obj;
415 ThreadInfoData threadInfo = obj as ThreadInfoData;
416 if (threadInfo == null) {
417 threadInfo = new ThreadInfoData(indent);
418 _ThreadNesting[Thread.CurrentThread.GetHashCode()] = threadInfo;
420 indent = threadInfo.Indent;
425 Object obj = _ThreadNesting[Thread.CurrentThread.GetHashCode()];
429 if (!GlobalLog.s_DebugCallNesting) {
430 _ThreadNesting[Thread.CurrentThread.GetHashCode()] = value;
432 ThreadInfoData threadInfo = obj as ThreadInfoData;
433 if (threadInfo == null) {
434 threadInfo = new ThreadInfoData(value);
435 _ThreadNesting[Thread.CurrentThread.GetHashCode()] = threadInfo;
437 threadInfo.Indent = value;
442 [System.Diagnostics.Conditional("TRAVE")]
443 private void IncNestingCount() {
444 IndentString = IndentString + " ";
447 [System.Diagnostics.Conditional("TRAVE")]
448 private void DecNestingCount() {
449 string indent = IndentString;
450 if (indent.Length>1) {
452 indent = indent.Substring(1);
455 indent = string.Empty;
458 if (indent.Length==0) {
461 IndentString = indent;
464 private string GetNestingString() {
468 [System.Diagnostics.Conditional("TRAVE")]
469 private void ValidatePush(string name) {
470 if (GlobalLog.s_DebugCallNesting) {
471 Object obj = _ThreadNesting[Thread.CurrentThread.GetHashCode()];
472 ThreadInfoData threadInfo = obj as ThreadInfoData;
473 if (threadInfo == null) {
476 threadInfo.NestingStack.Push(name);
480 [System.Diagnostics.Conditional("TRAVE")]
481 private void ValidatePop(string name) {
482 if (GlobalLog.s_DebugCallNesting) {
484 Object obj = _ThreadNesting[Thread.CurrentThread.GetHashCode()];
485 ThreadInfoData threadInfo = obj as ThreadInfoData;
486 if (threadInfo == null) {
489 if (threadInfo.NestingStack.Count == 0) {
490 PrintLine("++++====" + "Poped Empty Stack for :"+name);
492 string popedName = (string) threadInfo.NestingStack.Pop();
493 string [] parsedList = popedName.Split(new char [] {'(',')',' ','.',':',',','#'});
494 foreach (string element in parsedList) {
495 if (element != null && element.Length > 1 && name.IndexOf(element) != -1) {
499 PrintLine("++++====" + "Expected:" + popedName + ": got :" + name + ": StackSize:"+threadInfo.NestingStack.Count);
501 while(threadInfo.NestingStack.Count>0) {
502 string popedName2 = (string) threadInfo.NestingStack.Pop();
503 string [] parsedList2 = popedName2.Split(new char [] {'(',')',' ','.',':',',','#'});
504 foreach (string element2 in parsedList2) {
505 if (element2 != null && element2.Length > 1 && name.IndexOf(element2) != -1) {
512 PrintLine("++++====" + "ValidatePop failed for: "+name);
528 } // class LoggingObject
530 internal static class TraveHelper {
531 private static readonly string Hexizer = "0x{0:x}";
532 internal static string ToHex(object value) {
533 return String.Format(Hexizer, value);
539 internal class IntegerSwitch : BooleanSwitch {
540 public IntegerSwitch(string switchName, string switchDescription) : base(switchName, switchDescription) {
542 public new int Value {
544 return base.SwitchSetting;
552 internal enum ThreadKinds
556 // Mutually exclusive.
557 User = 0x0001, // Thread has entered via an API.
558 System = 0x0002, // Thread has entered via a system callback (e.g. completion port) or is our own thread.
560 // Mutually exclusive.
561 Sync = 0x0004, // Thread should block.
562 Async = 0x0008, // Thread should not block.
564 // Mutually exclusive, not always known for a user thread. Never changes.
565 Timer = 0x0010, // Thread is the timer thread. (Can't call user code.)
566 CompletionPort = 0x0020, // Thread is a ThreadPool completion-port thread.
567 Worker = 0x0040, // Thread is a ThreadPool worker thread.
568 Finalization = 0x0080, // Thread is the finalization thread.
569 Other = 0x0100, // Unknown source.
571 OwnerMask = User | System,
572 SyncMask = Sync | Async,
573 SourceMask = Timer | CompletionPort | Worker | Finalization | Other,
576 SafeSources = SourceMask & ~(Timer | Finalization), // Methods that "unsafe" sources can call must be explicitly marked.
577 ThreadPool = CompletionPort | Worker, // Like Thread.CurrentThread.IsThreadPoolThread
583 internal static class GlobalLog {
586 // Logging Initalization - I need to disable Logging code, and limit
587 // the effect it has when it is dissabled, so I use a bool here.
589 // This can only be set when the logging code is built and enabled.
590 // By specifing the "CSC_DEFINES=/D:TRAVE" in the build environment,
591 // this code will be built and then checks against an enviroment variable
592 // and a BooleanSwitch to see if any of the two have enabled logging.
595 private static BaseLoggingObject Logobject = GlobalLog.LoggingInitialize();
597 internal static LocalDataStoreSlot s_ThreadIdSlot;
598 internal static bool s_UseThreadId;
599 internal static bool s_UseTimeSpan;
600 internal static bool s_DumpWebData;
601 internal static bool s_UsePerfCounter;
602 internal static bool s_DebugCallNesting;
603 internal static bool s_DumpToConsole;
604 internal static int s_MaxDumpSize;
605 internal static string s_RootDirectory;
608 // Logging Config Variables - below are list of consts that can be used to config
612 // Max number of lines written into a buffer, before a save is invoked
613 // s_DumpToConsole disables.
614 public const int MaxLinesBeforeSave = 0;
617 [ReliabilityContract(Consistency.MayCorruptAppDomain, Cer.None)]
618 private static BaseLoggingObject LoggingInitialize() {
620 #if MONO_FEATURE_WEB_STACK
622 if (GetSwitchValue("SystemNetLogging", "System.Net logging module", false) &&
623 GetSwitchValue("SystemNetLog_ConnectionMonitor", "System.Net connection monitor thread", false)) {
624 InitConnectionMonitor();
627 #endif // MONO_FEATURE_WEB_STACK
629 // by default we'll log to c:\temp\ so that non interactive services (like w3wp.exe) that don't have environment
630 // variables can easily be debugged, note that the ACLs of the directory might need to be adjusted
631 if (!GetSwitchValue("SystemNetLog_OverrideDefaults", "System.Net log override default settings", false)) {
632 s_ThreadIdSlot = Thread.AllocateDataSlot();
633 s_UseThreadId = true;
634 s_UseTimeSpan = true;
635 s_DumpWebData = true;
637 s_UsePerfCounter = true;
638 s_DebugCallNesting = true;
639 s_DumpToConsole = false;
640 s_RootDirectory = "C:\\Temp\\";
641 return new LoggingObject();
643 if (GetSwitchValue("SystemNetLogging", "System.Net logging module", false)) {
644 s_ThreadIdSlot = Thread.AllocateDataSlot();
645 s_UseThreadId = GetSwitchValue("SystemNetLog_UseThreadId", "System.Net log display system thread id", false);
646 s_UseTimeSpan = GetSwitchValue("SystemNetLog_UseTimeSpan", "System.Net log display ticks as TimeSpan", false);
647 s_DumpWebData = GetSwitchValue("SystemNetLog_DumpWebData", "System.Net log display HTTP send/receive data", false);
648 s_MaxDumpSize = GetSwitchValue("SystemNetLog_MaxDumpSize", "System.Net log max size of display data", 256);
649 s_UsePerfCounter = GetSwitchValue("SystemNetLog_UsePerfCounter", "System.Net log use QueryPerformanceCounter() to get ticks ", false);
650 s_DebugCallNesting = GetSwitchValue("SystemNetLog_DebugCallNesting", "System.Net used to debug call nesting", false);
651 s_DumpToConsole = GetSwitchValue("SystemNetLog_DumpToConsole", "System.Net log to console", false);
652 s_RootDirectory = GetSwitchValue("SystemNetLog_RootDirectory", "System.Net root directory of log file", string.Empty);
653 return new LoggingObject();
656 return new BaseLoggingObject();
661 private static string GetSwitchValue(string switchName, string switchDescription, string defaultValue) {
662 new EnvironmentPermission(PermissionState.Unrestricted).Assert();
664 defaultValue = Environment.GetEnvironmentVariable(switchName);
667 EnvironmentPermission.RevertAssert();
672 private static int GetSwitchValue(string switchName, string switchDescription, int defaultValue) {
673 IntegerSwitch theSwitch = new IntegerSwitch(switchName, switchDescription);
674 if (theSwitch.Enabled) {
675 return theSwitch.Value;
677 new EnvironmentPermission(PermissionState.Unrestricted).Assert();
679 string environmentVar = Environment.GetEnvironmentVariable(switchName);
680 if (environmentVar!=null) {
681 defaultValue = Int32.Parse(environmentVar.Trim(), CultureInfo.InvariantCulture);
685 EnvironmentPermission.RevertAssert();
693 private static bool GetSwitchValue(string switchName, string switchDescription, bool defaultValue) {
694 BooleanSwitch theSwitch = new BooleanSwitch(switchName, switchDescription);
695 new EnvironmentPermission(PermissionState.Unrestricted).Assert();
697 if (theSwitch.Enabled) {
700 string environmentVar = Environment.GetEnvironmentVariable(switchName);
701 defaultValue = environmentVar!=null && environmentVar.Trim()=="1";
703 catch (ConfigurationException) { }
705 EnvironmentPermission.RevertAssert();
709 #endif // TRAVE || DEBUG
712 // Enables thread tracing, detects mis-use of threads.
715 private static Stack<ThreadKinds> t_ThreadKindStack;
717 private static Stack<ThreadKinds> ThreadKindStack
721 if (t_ThreadKindStack == null)
723 t_ThreadKindStack = new Stack<ThreadKinds>();
725 return t_ThreadKindStack;
730 internal static ThreadKinds CurrentThreadKind
735 return ThreadKindStack.Count > 0 ? ThreadKindStack.Peek() : ThreadKinds.Other;
737 return ThreadKinds.Unknown;
743 // ifdef'd instead of conditional since people are forced to handle the return value.
744 // [Conditional("DEBUG")]
745 [ReliabilityContract(Consistency.MayCorruptAppDomain, Cer.None)]
746 internal static IDisposable SetThreadKind(ThreadKinds kind)
748 if ((kind & ThreadKinds.SourceMask) != ThreadKinds.Unknown)
750 throw new InternalException();
753 // Ignore during shutdown.
754 if (NclUtilities.HasShutdownStarted)
759 ThreadKinds threadKind = CurrentThreadKind;
760 ThreadKinds source = threadKind & ThreadKinds.SourceMask;
763 // Special warnings when doing dangerous things on a thread.
764 if ((threadKind & ThreadKinds.User) != 0 && (kind & ThreadKinds.System) != 0)
766 Print("WARNING: Thread changed from User to System; user's thread shouldn't be hijacked.");
769 if ((threadKind & ThreadKinds.Async) != 0 && (kind & ThreadKinds.Sync) != 0)
771 Print("WARNING: Thread changed from Async to Sync, may block an Async thread.");
773 else if ((threadKind & (ThreadKinds.Other | ThreadKinds.CompletionPort)) == 0 && (kind & ThreadKinds.Sync) != 0)
775 Print("WARNING: Thread from a limited resource changed to Sync, may deadlock or bottleneck.");
779 ThreadKindStack.Push(
780 (((kind & ThreadKinds.OwnerMask) == 0 ? threadKind : kind) & ThreadKinds.OwnerMask) |
781 (((kind & ThreadKinds.SyncMask) == 0 ? threadKind : kind) & ThreadKinds.SyncMask) |
782 (kind & ~(ThreadKinds.OwnerMask | ThreadKinds.SyncMask)) |
786 if (CurrentThreadKind != threadKind)
788 Print("Thread becomes:(" + CurrentThreadKind.ToString() + ")");
792 return new ThreadKindFrame();
795 private class ThreadKindFrame : IDisposable
797 private int m_FrameNumber;
799 internal ThreadKindFrame()
801 m_FrameNumber = ThreadKindStack.Count;
804 void IDisposable.Dispose()
806 // Ignore during shutdown.
807 if (NclUtilities.HasShutdownStarted)
812 if (m_FrameNumber != ThreadKindStack.Count)
814 throw new InternalException();
817 ThreadKinds previous = ThreadKindStack.Pop();
820 if (CurrentThreadKind != previous)
822 Print("Thread reverts:(" + CurrentThreadKind.ToString() + ")");
829 [Conditional("DEBUG")]
830 [ReliabilityContract(Consistency.MayCorruptAppDomain, Cer.None)]
831 internal static void SetThreadSource(ThreadKinds source)
834 if ((source & ThreadKinds.SourceMask) != source || source == ThreadKinds.Unknown)
836 throw new ArgumentException("Must specify the thread source.", "source");
839 if (ThreadKindStack.Count == 0)
841 ThreadKindStack.Push(source);
845 if (ThreadKindStack.Count > 1)
847 Print("WARNING: SetThreadSource must be called at the base of the stack, or the stack has been corrupted.");
848 while (ThreadKindStack.Count > 1)
850 ThreadKindStack.Pop();
854 if (ThreadKindStack.Peek() != source)
856 // SQL can fail to clean up the stack, leaving the default Other at the bottom. Replace it.
857 Print("WARNING: The stack has been corrupted.");
858 ThreadKinds last = ThreadKindStack.Pop() & ThreadKinds.SourceMask;
859 Assert(last == source || last == ThreadKinds.Other, "Thread source changed.|Was:({0}) Now:({1})", last, source);
860 ThreadKindStack.Push(source);
865 [Conditional("DEBUG")]
866 [ReliabilityContract(Consistency.MayCorruptAppDomain, Cer.None)]
867 internal static void ThreadContract(ThreadKinds kind, string errorMsg)
869 ThreadContract(kind, ThreadKinds.SafeSources, errorMsg);
872 [Conditional("DEBUG")]
873 [ReliabilityContract(Consistency.MayCorruptAppDomain, Cer.None)]
874 internal static void ThreadContract(ThreadKinds kind, ThreadKinds allowedSources, string errorMsg)
876 if ((kind & ThreadKinds.SourceMask) != ThreadKinds.Unknown || (allowedSources & ThreadKinds.SourceMask) != allowedSources)
878 throw new InternalException();
881 ThreadKinds threadKind = CurrentThreadKind;
882 Assert((threadKind & allowedSources) != 0, errorMsg, "Thread Contract Violation.|Expected source:({0}) Actual source:({1})", allowedSources , threadKind & ThreadKinds.SourceMask);
883 Assert((threadKind & kind) == kind, errorMsg, "Thread Contract Violation.|Expected kind:({0}) Actual kind:({1})", kind, threadKind & ~ThreadKinds.SourceMask);
887 // Enables auto-hang detection, which will "snap" a log on hang
888 internal static bool EnableMonitorThread = false;
890 // Default value for hang timer
891 #if FEATURE_PAL // ROTORTODO - after speedups (like real JIT and GC) remove this
892 public const int DefaultTickValue = 1000*60*5; // 5 minutes
894 public const int DefaultTickValue = 1000*60; // 60 secs
895 #endif // FEATURE_PAL
898 [System.Diagnostics.Conditional("TRAVE")]
899 public static void AddToArray(string msg) {
901 GlobalLog.Logobject.PrintLine(msg);
905 [System.Diagnostics.Conditional("TRAVE")]
906 public static void Ignore(object msg) {
909 [System.Diagnostics.Conditional("TRAVE")]
910 [ReliabilityContract(Consistency.MayCorruptAppDomain, Cer.None)]
911 public static void Print(string msg) {
913 GlobalLog.Logobject.PrintLine(msg);
917 [System.Diagnostics.Conditional("TRAVE")]
918 public static void PrintHex(string msg, object value) {
920 GlobalLog.Logobject.PrintLine(msg+TraveHelper.ToHex(value));
924 [System.Diagnostics.Conditional("TRAVE")]
925 public static void Enter(string func) {
927 GlobalLog.Logobject.EnterFunc(func + "(*none*)");
931 [System.Diagnostics.Conditional("TRAVE")]
932 public static void Enter(string func, string parms) {
934 GlobalLog.Logobject.EnterFunc(func + "(" + parms + ")");
938 [Conditional("DEBUG")]
939 [Conditional("_FORCE_ASSERTS")]
940 [ReliabilityContract(Consistency.MayCorruptAppDomain, Cer.None)]
941 public static void Assert(bool condition, string messageFormat, params object[] data)
945 string fullMessage = string.Format(CultureInfo.InvariantCulture, messageFormat, data);
946 int pipeIndex = fullMessage.IndexOf('|');
953 int detailLength = fullMessage.Length - pipeIndex - 1;
954 Assert(fullMessage.Substring(0, pipeIndex), detailLength > 0 ? fullMessage.Substring(pipeIndex + 1, detailLength) : null);
959 [Conditional("DEBUG")]
960 [Conditional("_FORCE_ASSERTS")]
961 [ReliabilityContract(Consistency.MayCorruptAppDomain, Cer.None)]
962 public static void Assert(string message)
964 Assert(message, null);
967 [Conditional("DEBUG")]
968 [Conditional("_FORCE_ASSERTS")]
969 [ReliabilityContract(Consistency.MayCorruptAppDomain, Cer.None)]
970 public static void Assert(string message, string detailMessage)
974 Print("Assert: " + message + (!string.IsNullOrEmpty(detailMessage) ? ": " + detailMessage : ""));
976 Logobject.DumpArray(false);
981 Debug.Assert(false, message, detailMessage);
983 #if MONO_NOT_IMPLEMENTED
984 UnsafeNclNativeMethods.DebugBreak();
992 [System.Diagnostics.Conditional("TRAVE")]
993 public static void LeaveException(string func, Exception exception) {
995 GlobalLog.Logobject.LeaveFunc(func + " exception " + ((exception!=null) ? exception.Message : String.Empty));
999 [System.Diagnostics.Conditional("TRAVE")]
1000 public static void Leave(string func) {
1002 GlobalLog.Logobject.LeaveFunc(func + " returns ");
1006 [System.Diagnostics.Conditional("TRAVE")]
1007 public static void Leave(string func, string result) {
1009 GlobalLog.Logobject.LeaveFunc(func + " returns " + result);
1013 [System.Diagnostics.Conditional("TRAVE")]
1014 public static void Leave(string func, int returnval) {
1016 GlobalLog.Logobject.LeaveFunc(func + " returns " + returnval.ToString());
1020 [System.Diagnostics.Conditional("TRAVE")]
1021 public static void Leave(string func, bool returnval) {
1023 GlobalLog.Logobject.LeaveFunc(func + " returns " + returnval.ToString());
1027 [System.Diagnostics.Conditional("TRAVE")]
1028 public static void DumpArray() {
1030 GlobalLog.Logobject.DumpArray(true);
1034 [System.Diagnostics.Conditional("TRAVE")]
1035 public static void Dump(byte[] buffer) {
1037 Logobject.Dump(buffer, 0, buffer!=null ? buffer.Length : -1);
1041 [System.Diagnostics.Conditional("TRAVE")]
1042 public static void Dump(byte[] buffer, int length) {
1044 Logobject.Dump(buffer, 0, length);
1048 [System.Diagnostics.Conditional("TRAVE")]
1049 public static void Dump(byte[] buffer, int offset, int length) {
1051 Logobject.Dump(buffer, offset, length);
1055 [System.Diagnostics.Conditional("TRAVE")]
1056 public static void Dump(IntPtr buffer, int offset, int length) {
1058 Logobject.Dump(buffer, offset, length);
1062 #if MONO_FEATURE_WEB_STACK
1065 private class HttpWebRequestComparer : IComparer {
1071 HttpWebRequest x = (HttpWebRequest) x1;
1072 HttpWebRequest y = (HttpWebRequest) y1;
1074 if (x.GetHashCode() == y.GetHashCode()) {
1076 } else if (x.GetHashCode() < y.GetHashCode()) {
1078 } else if (x.GetHashCode() > y.GetHashCode()) {
1086 private class ConnectionMonitorEntry {
1087 public HttpWebRequest m_Request;
1089 public DateTime m_TimeAdded;
1090 public Connection m_Connection;
1092 public ConnectionMonitorEntry(HttpWebRequest request, Connection connection, int flags) {
1093 m_Request = request;
1094 m_Connection = connection;
1096 m_TimeAdded = DateTime.Now;
1100 private static volatile ManualResetEvent s_ShutdownEvent;
1101 private static volatile SortedList s_RequestList;
1103 internal const int WaitingForReadDoneFlag = 0x1;
1107 private static void ConnectionMonitor() {
1108 while(! s_ShutdownEvent.WaitOne(DefaultTickValue, false)) {
1109 if (GlobalLog.EnableMonitorThread) {
1111 GlobalLog.Logobject.LoggingMonitorTick();
1116 lock (s_RequestList) {
1117 DateTime dateNow = DateTime.Now;
1118 DateTime dateExpired = dateNow.AddSeconds(-DefaultTickValue);
1119 foreach (ConnectionMonitorEntry monitorEntry in s_RequestList.GetValueList() ) {
1120 if (monitorEntry != null &&
1121 (dateExpired > monitorEntry.m_TimeAdded))
1125 GlobalLog.Print("delay:" + (dateNow - monitorEntry.m_TimeAdded).TotalSeconds +
1126 " req#" + monitorEntry.m_Request.GetHashCode() +
1127 " cnt#" + monitorEntry.m_Connection.GetHashCode() +
1128 " flags:" + monitorEntry.m_Flags);
1131 monitorEntry.m_Connection.DebugMembers(monitorEntry.m_Request.GetHashCode());
1135 Assert(hungCount == 0, "Warning: Hang Detected on Connection(s) of greater than {0} ms. {1} request(s) hung.|Please Dump System.Net.GlobalLog.s_RequestList for pending requests, make sure your streams are calling Close(), and that your destination server is up.", DefaultTickValue, hungCount);
1141 [ReliabilityContract(Consistency.MayCorruptAppDomain, Cer.None)]
1142 internal static void AppDomainUnloadEvent(object sender, EventArgs e) {
1143 s_ShutdownEvent.Set();
1148 [System.Diagnostics.Conditional("DEBUG")]
1149 private static void InitConnectionMonitor() {
1150 s_RequestList = new SortedList(new HttpWebRequestComparer(), 10);
1151 s_ShutdownEvent = new ManualResetEvent(false);
1152 AppDomain.CurrentDomain.DomainUnload += new EventHandler(AppDomainUnloadEvent);
1153 AppDomain.CurrentDomain.ProcessExit += new EventHandler(AppDomainUnloadEvent);
1154 Thread threadMonitor = new Thread(new ThreadStart(ConnectionMonitor));
1155 threadMonitor.IsBackground = true;
1156 threadMonitor.Start();
1160 [System.Diagnostics.Conditional("DEBUG")]
1161 internal static void DebugAddRequest(HttpWebRequest request, Connection connection, int flags) {
1163 // null if the connection monitor is off
1164 if(s_RequestList == null)
1167 lock(s_RequestList) {
1168 Assert(!s_RequestList.ContainsKey(request), "s_RequestList.ContainsKey(request)|A HttpWebRequest should not be submitted twice.");
1170 ConnectionMonitorEntry requestEntry =
1171 new ConnectionMonitorEntry(request, connection, flags);
1174 s_RequestList.Add(request, requestEntry);
1181 [System.Diagnostics.Conditional("DEBUG")]
1182 internal static void DebugRemoveRequest(HttpWebRequest request) {
1184 // null if the connection monitor is off
1185 if(s_RequestList == null)
1188 lock(s_RequestList) {
1189 Assert(s_RequestList.ContainsKey(request), "!s_RequestList.ContainsKey(request)|A HttpWebRequest should not be removed twice.");
1192 s_RequestList.Remove(request);
1199 [System.Diagnostics.Conditional("DEBUG")]
1200 internal static void DebugUpdateRequest(HttpWebRequest request, Connection connection, int flags) {
1202 // null if the connection monitor is off
1203 if(s_RequestList == null)
1206 lock(s_RequestList) {
1207 if(!s_RequestList.ContainsKey(request)) {
1211 ConnectionMonitorEntry requestEntry =
1212 new ConnectionMonitorEntry(request, connection, flags);
1215 s_RequestList.Remove(request);
1216 s_RequestList.Add(request, requestEntry);
1223 } // class GlobalLog
1224 } // namespace System.Net