Production Debugging for .NET Framework Applications
Appendix
November 2002
Summary: The appendix contains listings for the code used in the walkthrough application. It also contains a section explaining how to use CorDbg as an alternative to WinDbg for debugging managed code.
This appendix contains the following:
- Thread state values. This contains a list of possible thread states and their descriptions.
- Application code. This lists the Visual C# code for the three ASP.NET applications used in the scenarios.
- Debugging with CorDbg. This shows you how to use CorDbg as an alternative to WinDbg for debugging managed code. It is an addendum to Chapter 3, "Debugging Contention Problems."
- Exploring further. This contains a list of articles to read for more information.
Contents
Thread State Values
Application Code
Debugging with CorDbg
Exploring Further
Thread State Values
The following table lists the possible thread states that are used to construct the thread state values reported by the !thread command of the SOS.dll debugger extension:
Table 5.1: Thread state values and descriptions
Mnemonic | Value | Description |
---|---|---|
TS_Unknown | 0x00000000 | Threads are initialized to null |
TS_StopRequested | 0x00000001 | Process will be stopped at the next opportunity |
TS_GCSuspendPending | 0x00000002 | Waiting to get to safe spot for garbage collector (GC) |
TS_UserSuspendPending | 0x00000004 | User suspension at the next opportunity |
TS_DebugSuspendPending | 0x00000008 | Indicates whether the debugger is suspending threads |
TS_GCOnTransitions | 0x00000010 | Indicates if a GC is forced on stub transitions (GCStress only) |
TS_LegalToJoin | 0x00000020 | Indicates if it is now legal to attempt a Join() |
TS_Hijacked | 0x00000080 | Return address has been hijacked |
TS_Background | 0x00000200 | Thread is a background thread |
TS_Unstarted | 0x00000400 | Thread has never been started |
TS_Dead | 0x00000800 | Thread is dead |
TS_WeOwn | 0x00001000 | Exposed object initiated this thread |
TS_CoInitialized | 0x00002000 | CoInitialize has been called for this thread |
TS_InSTA | 0x00004000 | Thread hosts an STA |
TS_InMTA | 0x00008000 | Thread is part of the MTA |
TS_ReportDead | 0x00010000 | Thread is in WaitForOtherThreads() |
TS_SyncSuspended | 0x00080000 | Thread is suspended with WaitSuspendEvent |
TS_DebugWillSync | 0x00100000 | Debugger will wait for this thread to sync |
TS_RedirectingEntryPoint | 0x00200000 | Redirecting entry point. Do not call managed entry point when set |
TS_SuspendUnstarted | 0x00400000 | Indicates latching a user suspension on an unstarted thread |
TS_ThreadPoolThread | 0x00800000 | Indicates if this is a thread pool thread |
TS_TPWorkerThread | 0x01000000 | Indicates if this is a thread pool worker thread (if not, it is a thread pool completion port thread) |
TS_Interruptible | 0x02000000 | Thread is sitting in either a Sleep(), Wait(), or Join() |
TS_Interrupted | 0x04000000 | Thread was awakened by an interrupt APC |
TS_AbortRequested | 0x08000000 | Process will be stopped at the next opportunity to trip the thread |
TS_AbortInitiated | 0x10000000 | Set when abort is begun |
TS_UserStopRequested | 0x20000000 | Set when a user stop is requested. This is different from TS_StopRequested |
TS_GuardPageGone | 0x40000000 | Stack overflow, not yet reset |
TS_Detached | 0x80000000 | Thread was detached by DllMain |
Application Code
This section of the appendix lists the Visual C#™ development tool code for the three ASP.NET applications used in the scenarios.
Contention.aspx.cs
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
namespace Debugging
{
/// <summary>
/// Summary description for Contention.
/// </summary>
public class Contention : System.Web.UI.Page
{
protected System.Web.UI.WebControls.Button btnObtainShared2;
protected System.Web.UI.WebControls.Button btnFreeShared;
protected System.Web.UI.WebControls.Button btnObtainShared3;
protected System.Web.UI.WebControls.Label Label1;
protected System.Web.UI.WebControls.Button btnObtainShared1;
private void Page_Load(object sender, System.EventArgs e)
{
PMHealth.OutputProcessInfoTable(Label1);
}
#region Web Form Designer generated code
override protected void OnInit(EventArgs e)
{
//
// CODEGEN: This call is required by the ASP.NET Web Form
//Designer.
//
InitializeComponent();
base.OnInit(e);
}
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.btnObtainShared2.Click += new
System.EventHandler(this.btnObtainShared2_Click);
this.btnFreeShared.Click += new
System.EventHandler(this.btnFreeShared_Click);
this.btnObtainShared3.Click += new
System.EventHandler(this.btnObtainShared3_Click);
this.btnObtainShared1.Click += new
System.EventHandler(this.btnObtainShared1_Click);
this.Load += new System.EventHandler(this.Page_Load);
}
#endregion
private void btnObtainShared1_Click(object sender,
System.EventArgs e)
{
SharedResource.Wait();
Label1.Text += "<BR>Obtained Shared Resource 1";
}
private void btnObtainShared2_Click(object sender,
System.EventArgs e)
{
SharedResource.Wait();
Label1.Text += "<BR>Obtained Shared Resource 2";
}
private void btnObtainShared3_Click(object sender,
System.EventArgs e)
{
SharedResource.Wait();
Label1.Text += "<BR>Obtained Shared Resource 3";
}
private void btnFreeShared_Click(object sender,
System.EventArgs e)
{
SharedResource.Free();
Label1.Text = "Freed Shared Resource";
SharedResource.Reset();
Label1.Text = Label1.Text += "<BR>Resetting Event";
}
}
}
Memory.aspx.cs
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Management;
/************************************************************
Title: Memory.aspx
Purpose: Running this ASP.NET page can demonstrate memory
consumption in either small or large increments.
To consider: How the Garbage Collector cleans up objects stored in
memory and how the size of those objects determines how, when, and if
the memory is every freed or reusable.
Partial Lab Instructions:
In the browser window, click Allocate 20 MB Objects once. Switch back
to Task Manager. Click the Performance tab and examine the Page File
Usage History. Click the same button again (2 total). Click the same
button once more (3 total) and immediately switch to the Performance
tab of Task Manager. Note: the sudden drop off.
Switch back to the browser window. Click Refresh Stats in the browser
window.
Note: There were two processes, PID 2740, and now a new process, ID
3128, and that 2740 was shutdown due to memory limit exceeded. (PID
numbers will vary from run to run.)
Examine the Application Event Log for Errors. Note: PID 2740 was
recycled because it exceeded 306 MB (60 of physical RAM)
Click the Refresh button on the browser page.
Using System Monitor. Note: Private Bytes and # Bytes in All Heaps
are both increasing.
Click the 20 MB Button once more.
Note: the Cache API Entries. And the # Bytes in all heaps. You can
also look at the Large Object Heap Size to determine that most of the
GC Heap memory is in the large object heap.
*************************************************************/
namespace Debugging
{
/// <summary>
/// Summary description for Memory.
/// </summary>
public class Memory : System.Web.UI.Page
{
protected System.Web.UI.WebControls.Label Label1;
protected System.Web.UI.WebControls.Button btn20MB;
protected System.Web.UI.WebControls.Button btnFree;
protected System.Web.UI.WebControls.Button btnRefresh;
protected System.Web.UI.WebControls.Button btn200K;
private void Page_Load(object sender,
System.EventArgs e)
{
PMHealth.OutputProcessInfoTable(Label1);
}
// Web Form Designer generated code omitted
private void btn20MB_Click(object sender,
System.EventArgs e)
{
//Allocate 20 MB objects
//Use a System.Web.SessionState Session object
//Get the CacheList Session object provided by
//ASP.NET
//If the object is null then populate it with
//a unique value.
if (Session["CacheList"] == null)
{
Session["CacheList"] = new ArrayList();
}
for (int i = 0; i< 5; i++)
{
long objSize = 20000000;
//Populate the variable with a unique value
string stime = DateTime.Now.Millisecond.ToString();
string cachekey = "LOCache-" + i.ToString() + ":" +
stime;
//System.Web.Caching.Cache Page.Cache
//Associate a key with a cached object
Cache[cachekey] = CreateLargeObject(objSize);
//Store the cache key in a Session scope
StoreCacheListInSession(cachekey);
}
PMHealth.OutputUpdatedMemoryStatsTable(Label1);
}
private byte[] CreateLargeObject(long size)
{
//Create and return a byte of specified size
byte[] largeByteArray = new byte[size];
return largeByteArray;
}
private void StoreCacheListInSession(string list)
{
//Store the list of cache keys in a Session object
//Specifically, dynamically populate an ArrayList with
//cached values and add to Session variable
ArrayList arr = (ArrayList)Session["CacheList"];
arr.Add(list);
Session["CacheList"] = arr;
}
private void btnFree_Click(object sender,
System.EventArgs e)
{
//Display message if the Session object is null.
if (Session["CacheList"] == null)
{
Label1.Text += "<TABLE BORDER>";
Label1.Text += "<TR><TD>No Entries in Cache (CacheList is
null)</TD></TR></TABLE>";
PMHealth.OutputGCTotalMemoryandCollect(Label1);
}
else
{
ArrayList arr = (ArrayList)Session["CacheList"];
if (arr.Count == 0)
{
Label1.Text += "<TABLE BORDER>";
Label1.Text += "<TR><TD>No Entries in Cache
(CacheList.Count is 0)</TD></TR></TABLE>";
PMHealth.OutputGCTotalMemoryandCollect(Label1);
}
else
{
//If Session object is populated, clear its contents.
Label1.Text += "<TABLE BORDER>";
Label1.Text += "<TR><TD><FONT COLOR=GREEN>";
Label1.Text += "Before Emptying Cache";
Label1.Text += "</FONT></TD></TR>";
Label1.Text += "<TR><TD><FONT COLOR=GREEN>";
//Retrieve the number of bytes currently thought to
//be allocated and convert to KB
Label1.Text += "GC.TotalMemory </TD><TD>" +
(GC.GetTotalMemory(false) / 1000).ToString() + " KB";
Label1.Text += "</FONT></TD></TR>";
Label1.Text += "<TR><TD><FONT COLOR=GREEN>";
//Get the amount of physical memory mapped to the
//process context and convert to KB
Label1.Text += "WorkingSet</TD><TD>" +
(Environment.WorkingSet / 1000).ToString() + " KB";
Label1.Text += "</FONT></TD></TR></TABLE>";
foreach (string s in arr)
{
if (Cache[s] != null)
{
//Remove each item from the cache
//using the cache key
Cache.Remove(s);
Label1.Text += "<TABLE BORDER>";
Label1.Text += "<TR><TD>";
Label1.Text +=
"Emptying out cachekey " + s;
Label1.Text += "</TD></TR></TABLE>";
}
}
//Remove elements from the arraylist and
//Session object
arr.Clear();
Session["CacheList"] = arr;
PMHealth.OutputGCTotalMemoryandCollect(Label1);
}
}
}
private void btnRefresh_Click(object sender,
System.EventArgs e)
{
PMHealth.OutputUpdatedMemoryStatsTable(Label1);
}
private void btn200K_Click(object sender,
System.EventArgs e)
{
//Allocate 200K objects
//Use a System.Web.SessionState.HttpSessionState
//Page.Session
//Get the CacheList Session object provided by
//ASP.NET. If the object is null then populate it
//with a unique value.
if (Session["CacheList"] == null)
{
Session["CacheList"] = new ArrayList();
}
for (int i = 0; i< 5; i++)
{
long objSize = 200000;
//Populate the variable with a unique value
string stime =
DateTime.Now.Millisecond.ToString();
string cachekey = "LOCache-" + i.ToString() +
":" + stime;
//System.Web.Caching.Cache Page.Cache
//Associate a key with a cached object
Cache[cachekey] = CreateLargeObject(objSize);
//Store the cache key in a Session scope
StoreCacheListInSession(cachekey);
}
}
}
}
Unexpected.aspx.cs
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using DebuggingCOMLib;
namespace Debugging
{
/// <summary>
/// Summary description for Unexpected.
/// </summary>
public class Unexpected : System.Web.UI.Page
{
protected System.Web.UI.WebControls.Label Label1;
protected System.Web.UI.WebControls.Button btnSTA;
protected System.Web.UI.WebControls.Button btnMTA;
private void Page_Load(object sender, System.EventArgs e)
{
PMHealth.OutputProcessInfoTable(Label1);
}
// Web Form Designer generated code omitted
private void btnSTA_Click(object sender,
System.EventArgs e)
{
DebuggingCOMLib.STAClass staobj =
new DebuggingCOMLib.STAClass();
staobj.CallCOM(1);
Label1.Text += "STA Call Completed successfully";
}
private void btnMTA_Click(object sender,
System.EventArgs e)
{
DebuggingCOMLib.MTAClass mtaobj =
new DebuggingCOMLib.MTAClass();
mtaobj.CallCOM(1);
Label1.Text += "MTA Call Completed sucessfully";
}
}
}
Pmhealth.cs
Pmhealth.cs contains the code that displays the Process Model statistics for the ASP.NET applications used in the scenario ASP.NET pages.
using System;
using System.Web;
using System.Runtime.InteropServices;
namespace Debugging
{
/// <summary>
/// Summary description for PMHealth.
/// </summary>
public class PMHealth
{
static PMHealth()
{
//
// TODO: Add constructor logic here
//
}
public static void
OutputProcessInfoTable(System.Web.UI.WebControls.Label lbl)
{
//ProcessModelInfo Class inherits from the System.Web
//Namespace.
//The static method GetHistory populates the
//ProcessInfo object.
//Properties of ProcessInfo provide information about
//the ASP.NET worker processes.
ProcessInfo[] history =
ProcessModelInfo.GetHistory(100);
for( int i=0; i<history.Length; i++ )
{
lbl.Text += "<TABLE BORDER>";
lbl.Text += "<TR><TD>";
//System.DateTime ProcessInfo.StartTime gets
//the time at which the process started.
lbl.Text += "StartTime<TD>" +
history[i].StartTime.ToString() + "<BR>";
lbl.Text += "<TR><TD>";
//System.TimeSpan ProcessInfo.Age gets the
//length of time the process has been running.
lbl.Text += "Age<TD>" +
history[i].Age.ToString() + "<BR>";
lbl.Text += "<TR><TD>";
//ProcessInfo.ProcessID. Get the ID assigned
//to the process.
lbl.Text += "ProcessID<TD>" +
history[i].ProcessID.ToString() + "<BR>";
lbl.Text += "<TR><TD>";
//ProcessInfo.RequestCount. Get the number of
//start requests.
lbl.Text += "RequestCount<TD>" +
history[i].RequestCount.ToString() + "<BR>";
lbl.Text += "<TR><TD>";
//System.String Memory.GetProcessStatus. Get
//the current status of a process.
lbl.Text += "Status<TD>" +
GetProcessStatus( history[i].Status ) + "<BR>";
lbl.Text += "<TR><TD>";
//System.String Memory.GetShutdownReason. Get
//the reason why a process shut down.
lbl.Text += "ShutdownReason<TD>" +
GetShutdownReason( history[i].ShutdownReason) + "<BR>";
lbl.Text += "<TR><TD>";
//ProcessInfo.PeakMemoryUsed gets the maximum
//amount of memory the process has used.
lbl.Text += "PeakMemoryUsed<TD>" +
history[i].PeakMemoryUsed.ToString() + "<BR>";
lbl.Text += "</TABLE><P><P>";
}
}
private static String GetProcessStatus( ProcessStatus ps )
{
//ProcessStatus indicates the current status of a
//process.
String s = "Unknown";
switch(ps)
{
//The process is running
case ProcessStatus.Alive:
s = "Alive";
break;
//The process has shut down normally after
//receiving a shut down message from the IIS process.
case ProcessStatus.ShutDown:
s = "Shutdown";
break;
//The process has begun to shut down.
case ProcessStatus.ShuttingDown:
s = "Shutting Down";
break;
//The process was forced to terminate by the
//IIS process.
case ProcessStatus.Terminated:
s = "Terminated";
break;
}
return s;
}
private static String GetShutdownReason(
ProcessShutdownReason psr )
{
//ProcessShutdownReason indicates why a process has
//shut down.
String s = "Unknown";
switch(psr)
{
//The process was restarted because a
//deadlock was suspected
case ProcessShutdownReason.DeadlockSuspected:
s = "Deadlock Suspected";
break;
//The process exceeded the allowable
//idle time.
case ProcessShutdownReason.IdleTimeout:
s = "Idle Timeout";
break;
//The process exceeded the per-process
//memory limit.
case ProcessShutdownReason.MemoryLimitExceeded:
s = "Memory Limit Exceeded";
break;
//No reason available
case ProcessShutdownReason.None:
s = "N/A";
break;
//The process was restarted because it
//didn't respond to a ping from the IIS process
case ProcessShutdownReason.PingFailed:
s = "Ping Failed";
break;
//Requests assigned to the process
//exceeded the allowable number in the queue.
case ProcessShutdownReason.RequestQueueLimit:
s = "Request Queue Limit";
break;
//Requests executed by the process
//exceeded the allowable limit.
case ProcessShutdownReason.RequestsLimit:
s = "Requests Limit";
break;
//The process restarted because it was
//alive longer than allowed.
case ProcessShutdownReason.Timeout:
s = "Timeout";
break;
//The process shut down unexpectedly.
case ProcessShutdownReason.Unexpected:
s = "Unexpected";
break;
}
return s;
}
public static void
OutputUpdatedMemoryStatsTable(System.Web.UI.WebControls.Label lbl)
{
//Update the Memory Statistics
lbl.Text += "<TABLE BORDER>";
lbl.Text += "<TR><TD><FONT COLOR=BLUE>";
lbl.Text += "Updated Memory Stats";
lbl.Text += "</FONT></TD><TD></TD></TR>";
lbl.Text += "<TR><TD><FONT COLOR=BLUE>";
//Retrieve the number of bytes currently thought to
//be allocated and convert to KB
lbl.Text += "GC.TotalMemory </TD><TD>" +
(GC.GetTotalMemory(false) / 1024).ToString() + " KB";
lbl.Text += "</FONT></TD></TR>";
lbl.Text += "<TR><TD><FONT COLOR=BLUE>";
//Get the amount of physical memory mapped to the
//process context and convert to KB
lbl.Text += "Private Bytes</TD><TD>" +
GetMemoryInfoFromOS() + " KB";
lbl.Text += "</FONT></TD></TR></TABLE>";
}
public static void
OutputGCTotalMemoryandCollect(System.Web.UI.WebControls.Label lbl)
{
lbl.Text += "<TABLE BORDER>";
lbl.Text += "<TR><TD><FONT COLOR=RED>";
//Display allocated memory before calling Garbage
//Collector
//Retrieve the number of bytes currently thought to
//be allocated and convert to KB
lbl.Text += "GC.TotalMemory </TD><TD>" +
(GC.GetTotalMemory(false) / 1024).ToString() + " KB";
lbl.Text += "</FONT></TD></TR></TABLE>";
//Force Garbage Collection of all Generations
//NOTE: Calling System.GC.Collect() manually can
//degrade performance of your application
// We call it in this lab so that you don't have
// to wait for a Generation 2 collection to
// occur before you can see the results in
// the heap.
GC.Collect();
lbl.Text += "<TABLE BORDER>";
lbl.Text += "<TR><TD><FONT COLOR=GREEN>";
//Display allocated memory after calling Garbage
//Collector
lbl.Text += "After GC.Collect";
lbl.Text += "</FONT></TD><TD></TD></TR>";
lbl.Text += "<TR><TD><FONT COLOR=GREEN>";
//Retrieve the number of bytes currently thought to
//be allocated and convert to KB
lbl.Text += "GC.TotalMemory </TD><TD>" +
(GC.GetTotalMemory(false) / 1024).ToString() + " KB";
lbl.Text += "</FONT></TD></TR>";
lbl.Text += "<TR><TD><FONT COLOR=GREEN>";
//Get the amount of physical memory mapped to the
//process context and convert to KB
lbl.Text += "Private Bytes</TD><TD>" +
GetMemoryInfoFromOS() + " KB";
lbl.Text += "</FONT></TD></TR></TABLE>";
}
[StructLayout(LayoutKind.Sequential)]
public class PROCESS_MEMORY_COUNTERS
{
public int cb;
public int PageFaultCount;
public int PeakWorkingSetSize;
public int WorkingSetSize;
public int QuotaPeakPagedPoolUsage;
public int QuotaPagedPoolUsage;
public int QuotaPeakNonPagedPoolUsage;
public int QuotaNonPagedPoolUsage;
public int PagefileUsage;
public int PeakPagefileUsage;
}
[DllImport("psapi.dll")]
public static extern int GetProcessMemoryInfo (
int hProcess,
[Out] PROCESS_MEMORY_COUNTERS counters,
int size
);
private static int GetMemoryInfoFromOS()
{
PROCESS_MEMORY_COUNTERS counters = new
PROCESS_MEMORY_COUNTERS();
GetProcessMemoryInfo (-1, counters, 40);
if (counters != null && counters.PagefileUsage != 0)
return counters.PagefileUsage/1024;
return 0;
}
}
}
Debugging with CorDbg
This section is an addendum to Chapter 3, "Debugging Contention Problems."
CorDbg provides an alternative to WinDbg for debugging managed code using a command line interface instead of a GUI. The difference between using this tool and using WinDbg is that you do not have to create a dump file or terminate the process.
This section shows you how to use CorDbg to attach to the Aspnet_wp.exe process, list the loaded modules in the process, and display call stack traces for specified threads. After listing specific CorDbg commands, there are examples of how to use these commands. Finally, there is an example showing you how to automate this process using a batch file.
Note For more information on CorDbg, see the Microsoft® .NET Framework SDK documentation and the CorDbg program Help.
The following table lists the commonly used CorDbg commands.
Table5.2: CorDbg commands and descriptions
Command | Description |
---|---|
pro [cessenum] | Enumerates all managed processes and the application domains in each process. |
a [ttach] pid | Attaches the debugger to the running process specified by the pid argument. |
l [ist] mod | Lists the loaded assemblies in the process by AppDomain. |
w [here] [count] | Displays a stack trace for the current thread. If you do not specify an argument, the tool displays a complete stack trace. If you specify an argument, the tool displays the specified number of stack frames. |
de [tach] | Detaches the debugger from the current process. The process automatically continues and runs as if a debugger is not attached to it. |
q [uit] | Stops the current process (if detach was not previously executed) and exits the debugger. |
? [command �] | Displays descriptions for the specified commands. If you do not specify any arguments, Cordbg.exe displays a list of debugger commands. |
Using CorDbg to Display Call Stack Information
Using CorDbg, you obtain the call stacks for the three threads created by the button-click events in Contention.aspx.
To display call stack information
To start the Aspnet_wp.exe process so that you can attach to it, browse to https://localhost/Debugging/Contention.aspx.
Click the three Obtain Shared Resource buttons on Contention.aspx. The page does not return data.
Open the Visual Studio .NET Command Prompt, and then type cordbg to start the debugger.
Note You need to have the .NET Framework SDK \Bin folder in your path to be able to run CorDbg. If you are using Visual Studio® .NET, you can open a Visual Studio .NET Command Prompt window, which has the path set correctly.
You should see a startup banner and prompt like the following:
Microsoft (R) Common Language Runtime Test Debugger Shell Version 1.0.3705.0 Copyright (C) Microsoft Corporation 1998-2001. All rights reserved. (cordbg)
Using the CorDbg pro command, find the Aspnet_wp.exe process ID among the listed running processes.
(cordbg) pro PID=0xab8 (3820) Name=C:\WINDOWS\Microsoft.NET\Framework\v1.0.3705\aspnet_wp.exe ID=2 AppDomainName=/LM/w3svc/1/root/Debugging-1- 126695838789138931 ID=1 AppDomainName=DefaultDomain
Note If you have other managed processes running, you will see other entries listed here. To ensure you are using the Aspnet_wp.exe process ID related to the correct browser session, close any other browser windows and other managed applications, and then restart IIS.
Attach the debugger to the running Aspnet_wp.exe process by using the attach command followed by the Aspnet_wp.exe process ID returned in the previous step.
Note that the symbols are not loaded for runtime components, so don't worry about the "cannot load symbol" warning messages. The first few lines of output from the command are shown below:
(cordbg) a 3820 Process 3820/0xab8 created. ...
List the loaded modules in the process using the l mod command.
The command line is shown below:
(cordbg) l mod
Display and examine the call stack trace for all current threads using the *w command. Specify an argument of 200; this lists up to 200 levels of stack trace.
(cordbg) *w 200
Now detach from the process, and quit the debugger:
(cordbg) de (cordbg) q
Using a Script File
An alternative to running each of the commands individually is to use a .cmd file that includes the commands and writes the output to a disk.
The code listing for managed_threads.cmd follows the output shown below. To run this file, make sure that managed_threads.cmd is located in the C:\Debuggers folder.
To run the script
Open a command prompt window, and then type iisreset at the prompt to restart IIS.
Browse to https://localhost/Debugging/contention.aspx.
Click the Obtain Shared Resource 1, 2,and 3 buttons.
At the command line, type the following:
C:\Debuggers>managed_threads.cmd 3820
Make sure that you replace "3280" with the ID of your Aspnet_wp.exe process.
The following listing shows the contents of the output file (C:\Debuggers\managed_threads.txt), with commands shown in bold:
Microsoft (R) Common Language Runtime Test Debugger Shell Version
1.0.3705.0
Copyright (C) Microsoft Corporation 1998-2001. All rights reserved.
(cordbg) a 3820
Process 3820/0xeec created.
Warning: couldn't load symbols for
c:\windows\microsoft.net\framework\v1.0.3705\mscorlib.dll
Warning: couldn't load symbols for
c:\windows\assembly\gac\system\1.0.3300.0__b77a5c561934e089\system.dll
Warning: couldn't load symbols for
c:\windows\assembly\gac\system.drawing\1.0.3300.0__b03f5f7f11d50a3
a\system.drawing.dll
Warning: couldn't load symbols for
c:\windows\assembly\gac\system.directoryservices\1.0.3300.0__b03f5f7f11d50a3a\
system.directoryservices.dll
Warning: couldn't load symbols for
c:\windows\assembly\gac\system.messaging\1.0.3300.0__b03f5f7f11d50a3a\
system.messaging.dll
Warning: couldn't load symbols for
c:\windows\assembly\gac\system.serviceprocess\1.0.3300.0__b03f5f7f11d50a3a\
system.serviceprocess.dll
Warning: couldn't load symbols for
c:\windows\assembly\gac\system.data\1.0.3300.0__b77a5c561934e089\system.data.dll
Warning: couldn't load symbols for
c:\windows\assembly\gac\system.web\1.0.3300.0__b03f5f7f11d50a3a\system.web.dll
Warning: couldn't load symbols for
c:\windows\assembly\gac\system.enterpriseservices\1.0.3300.0__b03f5f7f11d50a3a\
system.enterpriseservices.dll
Warning: couldn't load symbols for
c:\windows\assembly\gac\system.enterpriseservices\1.0.3300.0__b03f5f7f11d50a3a\
system.enterpriseservices.thunk.dll
Warning: couldn't load symbols for
c:\windows\assembly\gac\system.web.regularexpressions\1.0.3300.0__b03f5f7f11d50a3a
\system.web.regularexpressions.dll
Warning: couldn't load symbols for
c:\windows\assembly\gac\system.xml\1.0.3300.0__b77a5c561934e089\system.xml.dll
Warning: couldn't load symbols for
c:\windows\microsoft.net\framework\v1.0.3705\mscorlib.dll
Warning: couldn't load symbols for
c:\windows\assembly\gac\system\1.0.3300.0__b77a5c561934e089\system.dll
Warning: couldn't load symbols for
c:\windows\assembly\gac\system.drawing\1.0.3300.0__b03f5f7f11d50a3a\system.drawing.dll
Warning: couldn't load symbols for
c:\windows\assembly\gac\system.directoryservices\1.0.3300.0__b03f5f7f11d50a3a\
system.directoryservices.dll
Warning: couldn't load symbols for
c:\windows\assembly\gac\system.messaging\1.0.3300.0__b03f5f7f11d50a3a\
system.messaging.dll
Warning: couldn't load symbols for
c:\windows\assembly\gac\system.serviceprocess\1.0.3300.0__b03f5f7f11d50a3a\
system.serviceprocess.dll
Warning: couldn't load symbols for
c:\windows\assembly\gac\system.data\1.0.3300.0__b77a5c561934e089\system.data.dll
Warning: couldn't load symbols for
c:\windows\assembly\gac\system.web\1.0.3300.0__b03f5f7f11d50a3a\system.web.dll
Warning: couldn't load symbols for
c:\windows\assembly\gac\system.xml\1.0.3300.0__b77a5c561934e089\system.xml.dll
Warning: couldn't load symbols for
c:\windows\assembly\gac\system.web.regularexpressions\1.0.3300.0__b03f5f7f11d50a3a
\system.web.regularexpressions.dll
Warning: couldn't load symbols for
c:\windows\assembly\gac\system.enterpriseservices\1.0.3300.0__b03f5f7f11d50a3a\
system.enterpriseservices.dll
Warning: couldn't load symbols for
c:\windows\assembly\gac\system.enterpriseservices\1.0.3300.0__b03f5f7f11d50a3a\
system.enterpriseservices.thunk.dll
Warning: couldn't load symbols for
c:\windows\assembly\gac\system.web.services\1.0.3300.0__b03f5f7f11d50a3a\
system.web.services.dll
Warning: couldn't load symbols for
c:\windows\microsoft.net\framework\v1.0.3705\temporary asp.net
files\debugging\34374a37\79f52287\assembly\dl\2b680d64\198fa8c2_9d17c201\
interop.debuggingcomlib.dll
[thread 0xf30] Thread created.
Unable to determine existence of prolog, if any
[thread 0xe00] Thread created.
[thread 0xf40] Thread created.
[thread 0x6f4] Thread created.
[thread 0xd78] Thread created.
[thread 0xf30]
Thread 0xf30 R 0x7FFE0304: <unknown>
(cordbg) l mod
Module 0x00174f0c,
c:\windows\assembly\gac\system.drawing\1.0.3300.0__b03f5f7f11d50a3a\
system.drawing.dll -- AD #2 -- Symbols not loaded
Module 0x00135824,
c:\windows\assembly\gac\system.serviceprocess\1.0.3300.0__b03f5f7f11d50a3a\
system.serviceprocess.dll -- AD #1 -- Symbols not loaded
Module 0x00179404,
c:\windows\assembly\gac\system.serviceprocess\1.0.3300.0__b03f5f7f11d50a3a\
system.serviceprocess.dll -- AD #2 -- Symbols not loaded
Module 0x0016f3cc,
c:\windows\assembly\gac\system.xml\1.0.3300.0__b77a5c561934e089\
system.xml.dll -- AD #1 -- Symbols not loaded
Module 0x000b5ff4,
c:\windows\assembly\gac\system\1.0.3300.0__b77a5c561934e089\
system.dll -- AD #1 -- Symbols not loaded
Module 0x00177514,
c:\windows\assembly\gac\system.data\1.0.3300.0__b77a5c561934e089\
system.data.dll -- AD #2 -- Symbols not loaded
Module 0x0011897c,
c:\windows\assembly\gac\system.enterpriseservices\1.0.3300.0__b03f5f7f11d50a3a\
system.enterpriseservices.thunk.dll -- AD #1 -- Symbols not loaded
Module 0x001190ec,
c:\windows\assembly\gac\system.data\1.0.3300.0__b77a5c561934e089\
system.data.dll -- AD #1 -- Symbols not loaded
Module 0x00090ac4,
c:\windows\microsoft.net\framework\v1.0.3705\mscorlib.dll -- AD #1Symbols not loaded
Module 0x015dc294,
c:\windows\assembly\gac\system.web.services\1.0.3300.0__b03f5f7f11d50a3a\
system.web.services.dll -- AD #2 -- Symbols not loaded
Module 0x0017ad4c,
c:\windows\assembly\gac\system.web.regularexpressions\1.0.3300.0__b03f5f7f11d50a3a
\system.web.regularexpressions.dll -- AD #2 -- Symbols not loaded
Module 0x0017ae74,
c:\windows\assembly\gac\system.xml\1.0.3300.0__b77a5c561934e089\
system.xml.dll -- AD #2 -- Symbols not loaded
Module 0x015db804,
c:\windows\microsoft.net\framework\v1.0.3705\temporary asp.net
files\debugging\34374a37\79f52287\pvnt75wl.dll -- AD #2
Module 0x0017f99c,
c:\windows\microsoft.net\framework\v1.0.3705\temporary asp.net
files\debugging\34374a37\79f52287\assembly\dl\18040135\6ef006c4_9d17c201\
debugging.dll -- AD #2
Module 0x00178fbc,
c:\windows\assembly\gac\system.web\1.0.3300.0__b03f5f7f11d50a3a\
system.web.dll -- AD #2 -- Symbols not loaded
Module 0x001755fc,
c:\windows\assembly\gac\system.directoryservices\1.0.3300.0__b03f5f7f11d50a3a\
system.directoryservices.dll -- AD #2 -- Symbols not loaded
Module 0x00171efc,
c:\windows\microsoft.net\framework\v1.0.3705\mscorlib.dll -- AD #2Symbols not loaded
Module 0x0016a894,
c:\windows\microsoft.net\framework\v1.0.3705\temporary asp.net
files\debugging\34374a37\79f52287\assembly\dl\2b680d64\198fa8c2_9d17c201\
interop.debuggingcomlib.dll -- AD #2 -- Symbols not loaded
Module 0x00142ccc,
c:\windows\assembly\gac\system.web\1.0.3300.0__b03f5f7f11d50a3a\
system.web.dll -- AD #1 -- Symbols not loaded
Module 0x0010b2ac,
c:\windows\assembly\gac\system.directoryservices\1.0.3300.0__b03f5f7f11d50a3a\
system.directoryservices.dll -- AD #1 -- Symbols not loaded
Module 0x0016ba8c,
c:\windows\assembly\gac\system\1.0.3300.0__b77a5c561934e089\system.dllAD #2 -- Symbols not loaded
Module 0x00142ba4,
c:\windows\assembly\gac\system.enterpriseservices\1.0.3300.0__b03f5f7f11d50a3a\
system.enterpriseservices.dll -- AD #1 -- Symbols not loaded
Module 0x0011880c,
c:\windows\assembly\gac\system.messaging\1.0.3300.0__b03f5f7f11d50a3a\
system.messaging.dll -- AD #1 -- Symbols not loaded
Module 0x000bd6b4,
c:\windows\assembly\gac\system.drawing\1.0.3300.0__b03f5f7f11d50a3a\
system.drawing.dll -- AD #1 -- Symbols not loaded
Module 0x015da5b4,
c:\windows\assembly\gac\system.enterpriseservices\1.0.3300.0__b03f5f7f11d50a3a\
system.enterpriseservices.thunk.dll -- AD #2 -- Symbols not loaded
Module 0x015d6dbc,
c:\windows\assembly\gac\system.enterpriseservices\1.0.3300.0__b03f5f7f11d50a3a\
system.enterpriseservices.dll -- AD #2 -- Symbols not loaded
Module 0x0017718c,
c:\windows\microsoft.net\framework\v1.0.3705\temporary asp.net
files\debugging\34374a37\79f52287\0rzdgjzl.dll -- AD #2
Module 0x001770fc,
c:\windows\assembly\gac\system.messaging\1.0.3300.0__b03f5f7f11d50a3a\
system.messaging.dll -- AD #2 -- Symbols not loaded
Module 0x00142c34,
c:\windows\assembly\gac\system.web.regularexpressions\1.0.3300.0__b03f5f7f11d50a3a
\system.web.regularexpressions.dll -- AD #1 -- Symbols not loaded
(cordbg) *w 200
Thread 0xd78 R 0x7FFE0304: <unknown>
Thread 0xd78 Current State:Normal
* 0x7FFE0304: <unknown>
--- Unmanaged transition ---
0) mscorlib!System.Threading.WaitHandle::WaitOne +0036 [no source
information available]
1) debugging!Debugging.SharedResource::Wait +005b in
C:\Inetpub\wwwroot\Debugging\SharedResource.cs:55
2) debugging!Debugging.Contention::btnObtainShared3_Click +0013 in
c:\inetpub\wwwroot\debugging\contention.aspx.cs:71
sender=(0x012113a8) <System.Web.UI.WebControls.Button>
e=(0x012193c4) <System.EventArgs>
3) system.web!System.Web.UI.WebControls.Button::OnClick +006d [no
source information available]
4) system.web!System.Web.UI.WebControls.Button::System.Web.UI.
IPostBackEventHandler.RaisePostBackEvent +003a [no source information available]
5) system.web!System.Web.UI.Page::RaisePostBackEvent +0013 [no
source information available]
6) system.web!System.Web.UI.Page::RaisePostBackEvent +0022 [no
source information available]
7) system.web!System.Web.UI.Page::ProcessRequestMain +04f0 [no
source information available]
8) system.web!System.Web.UI.Page::ProcessRequest +0077 [no source
information available]
9) system.web!System.Web.UI.Page::ProcessRequest +0013 [no source
information available]
10) system.web!CallHandlerExecutionStep::Execute +00b4 [no source
information available]
11) system.web!System.Web.HttpApplication::ExecuteStep +0058 [no
source information available]
12) system.web!System.Web.HttpApplication::ResumeSteps +00f3 [no
source information available]
13) system.web!System.Web.HttpApplication::System.Web.
IHttpAsyncHandler.BeginProcessRequest +00e3 [no source information available]
14) system.web!System.Web.HttpRuntime::ProcessRequestInternal +01e0
[no source information available]
15) system.web!System.Web.HttpRuntime::ProcessRequest +003d [no
source information available]
16) system.web!System.Web.Hosting.ISAPIRuntime::ProcessRequest +00b7
[no source information available]
--- Managed transition ---
0x00421EAE: <unknown>
Thread 0xf30 R 0x7FFE0304: <unknown>
Thread 0xf30 Current State:Normal
* 0x7FFE0304: <unknown>
--- Unmanaged transition ---
0) mscorlib!System.Threading.WaitHandle::WaitOne +0036 [no source
information available]
1) debugging!Debugging.SharedResource::Wait +005b in
C:\Inetpub\wwwroot\Debugging\SharedResource.cs:55
2) debugging!Debugging.Contention::btnObtainShared1_Click +0014 in
c:\inetpub\wwwroot\debugging\contention.aspx.cs:59
sender=(0x011e91c4) <System.Web.UI.WebControls.Button>
e=(0x011f136c) <System.EventArgs>
3) system.web!System.Web.UI.WebControls.Button::OnClick +006d [no
source information available]
4) system.web!System.Web.UI.WebControls.Button::System.Web.UI.
IPostBackEventHandler.RaisePostBackEvent +003a [no source information available]
5) system.web!System.Web.UI.Page::RaisePostBackEvent +0013 [no
source information available]
6) system.web!System.Web.UI.Page::RaisePostBackEvent +0022 [no
source information available]
7) system.web!System.Web.UI.Page::ProcessRequestMain +04f0 [no
source information available]
8) system.web!System.Web.UI.Page::ProcessRequest +0077 [no source
information available]
9) system.web!System.Web.UI.Page::ProcessRequest +0013 [no source
information available]
10) system.web!CallHandlerExecutionStep::Execute +00b4 [no source
information available]
11) system.web!System.Web.HttpApplication::ExecuteStep +0058 [no
source information available]
12) system.web!System.Web.HttpApplication::ResumeSteps +00f3 [no
source information available]
13) system.web!System.Web.HttpApplication::System.Web.
IHttpAsyncHandler.BeginProcessRequest +00e3 [no source information available]
14) system.web!System.Web.HttpRuntime::ProcessRequestInternal +01e0
[no source information available]
15) system.web!System.Web.HttpRuntime::ProcessRequest +003d [no
source information available]
16) system.web!System.Web.Hosting.ISAPIRuntime::ProcessRequest +00b7
[no source information available]
--- Managed transition ---
0x00421EAE: <unknown>
Thread 0x6f4 R 0x7FFE0304: <unknown>
Thread 0x6f4 Current State:Normal
* 0x7FFE0304: <unknown>
--- Unmanaged transition ---
0) mscorlib!System.Threading.WaitHandle::WaitOne +0036 [no source
information available]
1) debugging!Debugging.SharedResource::Wait +005b in
C:\Inetpub\wwwroot\Debugging\SharedResource.cs:55
2) debugging!Debugging.Contention::btnObtainShared2_Click +0013 in
c:\inetpub\wwwroot\debugging\contention.aspx.cs:65
sender=(0x012043ec) <System.Web.UI.WebControls.Button>
e=(0x0120c888) <System.EventArgs>
3) system.web!System.Web.UI.WebControls.Button::OnClick +006d [no
source information available]
4) system.web!System.Web.UI.WebControls.Button::System.Web.UI.
IPostBackEventHandler.RaisePostBackEvent +003a [no source information available]
5) system.web!System.Web.UI.Page::RaisePostBackEvent +0013 [no
source information available]
6) system.web!System.Web.UI.Page::RaisePostBackEvent +0022 [no
source information available]
7) system.web!System.Web.UI.Page::ProcessRequestMain +04f0 [no
source information available]
8) system.web!System.Web.UI.Page::ProcessRequest +0077 [no source
information available]
9) system.web!System.Web.UI.Page::ProcessRequest +0013 [no source
information available]
10) system.web!CallHandlerExecutionStep::Execute +00b4 [no source
information available]
11) system.web!System.Web.HttpApplication::ExecuteStep +0058 [no
source information available]
12) system.web!System.Web.HttpApplication::ResumeSteps +00f3 [no
source information available]
13) system.web!System.Web.HttpApplication::System.Web.
IHttpAsyncHandler.BeginProcessRequest +00e3 [no source information available]
14) system.web!System.Web.HttpRuntime::ProcessRequestInternal +01e0
[no source information available]
15) system.web!System.Web.HttpRuntime::ProcessRequest +003d [no
source information available]
16) system.web!System.Web.Hosting.ISAPIRuntime::ProcessRequest +00b7
[no source information available]
--- Managed transition ---
0x00421EAE: <unknown>
Thread 0xe00 R 0x7FFE0304: <unknown>
Thread 0xe00 Current State:Background
* 0x7FFE0304: <unknown>
Thread 0xf40 R 0x7FFE0304: <unknown>
Thread 0xf40 Current State:Background
* 0x7FFE0304: <unknown>
(cordbg) de
(cordbg) q
The managed_threads.cmd Script
This is the code listing for the script that produced the output in the previous section:
@echo off
if "%_echo%"=="1" echo on
setlocal
REM FILENAME: MANAGED_THREADS.CMD
REM PURPOSE: To Dump the managed threads for an .NET Process
REM DATE: 5/9/2002
REM AUTHOR: SIE, GSSC, Microsoft Corporation
if /i "%1" == "" (
GOTO :HELP
) else (
cordbg !a %1 !l mod !*w 200 !de !q >managed_threads.txt
echo managed threads output is in managed_threads.txt
GOTO :EOF
)
:HELP
echo.
echo USAGE: %~xn0 [process ID from TLIST.EXE]
echo.
echo %~xn0 will create a log of the managed threads in a .NET Application
echo.
echo For Example:
tlist
goto :EOF
:EOF
endlocal
Exploring Further
For more information, read the following articles:
- "COM Threading and Application Architecture in COM+ Applications" on the MSDN Web site at https://msdn.microsoft.com/library/default.asp?url=/library/en-us/dncomser/html/comthread.asp
- "Thread.ApartmentState Property" on the MSDN Web site at https://msdn.microsoft.com/library/en-us/cpref/html/frlrfSystemThreadingThreadClassApartmentStateTopic.asp
- "STAThreadAttribute Class" on the MSDN Web site at https://msdn.microsoft.com/library/en-us/cpref/html/frlrfSystemSTAThreadAttributeClassTopic.asp
- "MTAThreadAttribute Class" on the MSDN Web site at https://msdn.microsoft.com/library/en-us/cpref/html/frlrfSystemMTAThreadAttributeClassTopic.asp
- Article Q303375, "INFO: XML Web Services and Apartment Objects" in the Microsoft Knowledge Base at https://support.microsoft.com/default.aspx?scid=kb;en-us;Q303375
- Article Q308095, "PRB: Creating STA Components in the Constructor in ASP.NET ASPCOMPAT Mode Negatively Affects Performance" in the Microsoft Knowledge Base at https://support.microsoft.com/default.aspx?scid=kb;en-us;Q308095
- "FIX: Various Problems When You Call Transactional COM+ Components from ASP.NET (Q318000)" on the Microsoft Product Support Services Web site at https://support.microsoft.com/default.aspx?scid=fh;EN-US;Q318000
- "HOWTO: Set the COM Apartment Type in Managed Threads (Q318402)� on the Microsoft Product Support Services Web site at https://support.microsoft.com/default.aspx?scid=fh;EN-US;318402
- Article Q318000, "FIX: Problems When You Call Transactional COM+ Components" in the Microsoft Knowledge Base at https://support.microsoft.com/default.aspx?scid=fh;EN-US;318000
- Article Q309330, "BUG: InvalidCastException Calling COM Component Marked as STA" in the Microsoft Knowledge Base at https://support.microsoft.com/default.aspx?scid=fh;EN-US;309330
- Article Q291837, "INFO: Do Not Make Blocking Calls from an STA Component" in the Microsoft Knowledge Base at https://support.microsoft.com/default.aspx?scid=fh;EN-US;291837