<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Ingo Rammer's Weblog</title><link>http://blogs.thinktecture.com/ingo/default.aspx</link><description /><dc:language>en-US</dc:language><generator>CommunityServer 1.1 (Build: 1.1.0.50615)</generator><item><title>Slides, Demos and Notes for TechDays Ghent and DevWeek London</title><link>http://blogs.thinktecture.com/ingo/archive/2008/03/16/415125.aspx</link><pubDate>Sun, 16 Mar 2008 18:10:00 GMT</pubDate><guid isPermaLink="false">ff4ed322-7612-4f43-9d7f-220c081c7cfd:415125</guid><dc:creator>Ingo</dc:creator><slash:comments>3</slash:comments><comments>http://blogs.thinktecture.com/ingo/comments/415125.aspx</comments><wfw:commentRss>http://blogs.thinktecture.com/ingo/commentrss.aspx?PostID=415125</wfw:commentRss><description>Thanks for attending one of my sessions at the recent TechDays in Ghent or at DevWeek in London. As announced during the sessions, I have uploaded all materials and you can access them at the following locations:&lt;br&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.thinktecture.com/media/9495/ingorammer_debugging_devweeklondon2008.zip"&gt;Slides, Samples and Notes for DevWeek London (Debugging)&lt;/a&gt; - ZIP, 1.10 MB&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.thinktecture.com/media/9502/ingorammer_techdaysgent2008.zip"&gt;Slides and Samples for TechDays in Ghent (WCF/WF Integration and Debugging)&lt;/a&gt; - ZIP, 1.80 MB&lt;br&gt;&lt;/li&gt;&lt;/ul&gt;&lt;img src="http://blogs.thinktecture.com/aggbug.aspx?PostID=415125" width="1" height="1"&gt;</description></item><item><title>Slides and Demos for Prio Conference</title><link>http://blogs.thinktecture.com/ingo/archive/2007/11/15/415030.aspx</link><pubDate>Thu, 15 Nov 2007 14:33:00 GMT</pubDate><guid isPermaLink="false">ff4ed322-7612-4f43-9d7f-220c081c7cfd:415030</guid><dc:creator>Ingo</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.thinktecture.com/ingo/comments/415030.aspx</comments><wfw:commentRss>http://blogs.thinktecture.com/ingo/commentrss.aspx?PostID=415030</wfw:commentRss><description>I've just uploaded the slides and demos for my debugging talks at Prio Conference. (Most of the materials will be in German).
&lt;br&gt;&lt;br&gt;
&lt;i&gt;&lt;b&gt;Download&lt;/b&gt;&lt;/i&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://static.thinktecture.com/conferences/prio/AdvancedDebugging_IngoRammer.pptx"&gt;Slide Deck: Advanced Debugging (PPTX, 4.553 KB)&lt;/a&gt;
&lt;/li&gt;&lt;li&gt;&lt;a href="http://static.thinktecture.com/conferences/prio/ProductionDebugging_IngoRammer.pptx"&gt;Slide Deck: Production Debugging (PPTX, 4.527 KB)&lt;/a&gt;
&lt;/li&gt;&lt;li&gt;&lt;a href="http://static.thinktecture.com/conferences/prio/notes.txt"&gt;Online Notes for Production Debugging (TXT, 2 KB)&lt;/a&gt;
&lt;/li&gt;&lt;li&gt;&lt;a href="http://static.thinktecture.com/conferences/prio/DebuggingDemos_Prio.zip"&gt;Demo Applications for both talks (ZIP, 7.941 KB)&lt;/a&gt;
&lt;/li&gt;&lt;/ul&gt;

&lt;i&gt;&lt;b&gt;&lt;/b&gt;&lt;/i&gt;&lt;br&gt;&lt;img src="http://blogs.thinktecture.com/aggbug.aspx?PostID=415030" width="1" height="1"&gt;</description></item><item><title>Notes for my TechEd Europe Talk - Hardcore Production Debugging</title><link>http://blogs.thinktecture.com/ingo/archive/2007/11/10/415021.aspx</link><pubDate>Sat, 10 Nov 2007 08:32:00 GMT</pubDate><guid isPermaLink="false">ff4ed322-7612-4f43-9d7f-220c081c7cfd:415021</guid><dc:creator>Ingo</dc:creator><slash:comments>6</slash:comments><comments>http://blogs.thinktecture.com/ingo/comments/415021.aspx</comments><wfw:commentRss>http://blogs.thinktecture.com/ingo/commentrss.aspx?PostID=415021</wfw:commentRss><description>As announced during my talk, I've uploaded my notes and samples for the session on production debugging. You can download them here:&lt;br&gt;&lt;ul&gt;&lt;li&gt;Demo: &lt;a href="http://static.thinktecture.com/conferences/reallybuggyapplication.zip"&gt;ReallyBuggyApplication.zip&lt;/a&gt; (122 kb)&lt;/li&gt;&lt;li&gt;Notes: &lt;a href="http://static.thinktecture.com/conferences/debuggingnotes.txt"&gt;DebuggingNotes.txt&lt;/a&gt; (2kb)&lt;/li&gt;&lt;/ul&gt;Thanks for being there! I hope that you've enjoyed the session.&lt;br&gt;&lt;img src="http://blogs.thinktecture.com/aggbug.aspx?PostID=415021" width="1" height="1"&gt;</description></item><item><title>Dominick Baier joins thinktecture</title><link>http://blogs.thinktecture.com/ingo/archive/2007/02/12/414796.aspx</link><pubDate>Mon, 12 Feb 2007 15:54:00 GMT</pubDate><guid isPermaLink="false">ff4ed322-7612-4f43-9d7f-220c081c7cfd:414796</guid><dc:creator>Ingo</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.thinktecture.com/ingo/comments/414796.aspx</comments><wfw:commentRss>http://blogs.thinktecture.com/ingo/commentrss.aspx?PostID=414796</wfw:commentRss><description>Well ... it's been inofficially known for quite a while, but today I'm proud to finally publicly annouce that .NET security wizard &lt;a href="http://www.thinktecture.com/staff/dominick"&gt;Dominick Baier&lt;/a&gt; has joined thinktecture as a consultant. I think that this is especially great as his in-depth security knowledge and experience (before going to .NET he used to work as a network penetration tester and a ISO certified security auditor) is really adding a lot of value to our combined knowledge. (And most importantly ... he's just a great guy to work with ...)&lt;br&gt;&lt;br&gt;Dominick is also the one wrote one of the only .NET books I've read cover-to-cover in the recent months because it contained so much valueable content: &lt;a href="http://www.amazon.com/dp/0735623317"&gt;Developing More Secure ASP.NET Applications&lt;/a&gt;.&lt;br&gt;&lt;img src="http://blogs.thinktecture.com/aggbug.aspx?PostID=414796" width="1" height="1"&gt;</description></item><item><title>thinktecture @ TechEd Europe Developers </title><link>http://blogs.thinktecture.com/ingo/archive/2006/11/03/414739.aspx</link><pubDate>Fri, 03 Nov 2006 12:08:00 GMT</pubDate><guid isPermaLink="false">ff4ed322-7612-4f43-9d7f-220c081c7cfd:414739</guid><dc:creator>Ingo</dc:creator><slash:comments>6</slash:comments><comments>http://blogs.thinktecture.com/ingo/comments/414739.aspx</comments><wfw:commentRss>http://blogs.thinktecture.com/ingo/commentrss.aspx?PostID=414739</wfw:commentRss><description>It's that time of the year again and in a few days, the European thinktects will get together at Microsoft's biggest gathering of developers in Europe. This time, we have a pretty intense schedule:&lt;br&gt;&lt;br&gt;&lt;b&gt;Monday&lt;br&gt;&lt;/b&gt;PRE008, 12:00 - 19:00, Ingo Rammer and Christian Weyer, &lt;i&gt;&lt;b&gt;Windows Workflow Foundation (WF) - Free Workflow Support for your Applications&lt;/b&gt;&lt;/i&gt;&lt;br&gt;&lt;br&gt;&lt;b&gt;Wednesday&lt;br&gt;&lt;/b&gt;DEV001, 13:30 - 14:45, Neno Loje, &lt;b&gt;&lt;i&gt;DEMO: Adopting ClickOnce for Real World Applications&lt;/i&gt;&lt;/b&gt;&lt;br&gt;&lt;br&gt;&lt;b&gt;Thursday&lt;br&gt;&lt;/b&gt;DEVWD15, 09:00 - 10:15, Ingo Rammer, &lt;i&gt;&lt;b&gt;Hardcore .NET Production Debugging&lt;/b&gt;&lt;/i&gt;&lt;br&gt;DEVWD17, 09:00 - 10:15, Neno Loje, &lt;i&gt;&lt;b&gt;Team System Adoption Best Practices&lt;/b&gt;&lt;/i&gt;&lt;br&gt;DEVWD15, 13:30 - 14:45, Ingo Rammer, &lt;b&gt;&lt;i&gt;Hardcore .NET Production Debugging (repeat)&lt;/i&gt;&lt;/b&gt;&lt;br&gt;DEVWD17, 15:45 - 17:00, Neno Loje, &lt;b&gt;&lt;i&gt;Team System Adoption Best Practices (repeat)&lt;/i&gt;&lt;/b&gt;&lt;br&gt;ARC309, 17:30 - 18:45, Dominick Baier, &lt;i&gt;&lt;b&gt;Security is a Feature - Best Practices for Designing Secure Distributed .NET Applications&lt;/b&gt;&lt;/i&gt;&lt;br&gt;&lt;br&gt;&lt;b&gt;Friday&lt;br&gt;&lt;/b&gt;DEV403, 09:00 - 10:15, Ingo Rammer, &lt;b&gt;Optimizing Performance and Scalability of Distributed .NET Applications&lt;/b&gt;&lt;br&gt;DEV004, 13:30 - 14:45, Christian Weyer, &lt;b&gt;DEMO: Technology in Action! Building a Distributed Solution with .NET Framework 3.0&lt;/b&gt;&lt;br&gt;&lt;br&gt;I'm really looking forward to meeting you in Barcelona!&lt;br&gt;&lt;br&gt;Update: Slides, samples and notes are online at &lt;a target="_new" href="http://www.thinktecture.com/Conferences/slides/TechEd2006/default.html"&gt;http://www.thinktecture.com/Conferences/slides/TechEd2006/default.html&lt;/a&gt;.&lt;img src="http://blogs.thinktecture.com/aggbug.aspx?PostID=414739" width="1" height="1"&gt;</description></item><item><title>Slides and Demos for the MSDN Event in Brussels</title><link>http://blogs.thinktecture.com/ingo/archive/2006/09/26/414707.aspx</link><pubDate>Tue, 26 Sep 2006 06:37:00 GMT</pubDate><guid isPermaLink="false">ff4ed322-7612-4f43-9d7f-220c081c7cfd:414707</guid><dc:creator>Ingo</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.thinktecture.com/ingo/comments/414707.aspx</comments><wfw:commentRss>http://blogs.thinktecture.com/ingo/commentrss.aspx?PostID=414707</wfw:commentRss><description>As announced during the event, I have uploaded my slides and demos from yesterday's MSDN Event in Brussels to &lt;a href="http://www.thinktecture.com/Conferences/slides/MsdnBrussels"&gt;http://www.thinktecture.com/Conferences/slides/MsdnBrussels&lt;/a&gt;. Enjoy!&lt;br&gt;&lt;img src="http://blogs.thinktecture.com/aggbug.aspx?PostID=414707" width="1" height="1"&gt;</description></item><item><title>Off to Basta!2006</title><link>http://blogs.thinktecture.com/ingo/archive/2006/09/18/414700.aspx</link><pubDate>Mon, 18 Sep 2006 12:07:00 GMT</pubDate><guid isPermaLink="false">ff4ed322-7612-4f43-9d7f-220c081c7cfd:414700</guid><dc:creator>Ingo</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.thinktecture.com/ingo/comments/414700.aspx</comments><wfw:commentRss>http://blogs.thinktecture.com/ingo/commentrss.aspx?PostID=414700</wfw:commentRss><description>In a few hours I'm off to Basta!2006. I'm really looking forward as this year thinktecture has a massive presence - even running in some parallel slots - at this conference. It's also the first time that the four of us in Europe meet in the current line-up as &lt;a href="http://www.nenoloje.de/"&gt;Neno Loje&lt;/a&gt; joined a few weeks ago to add his great &lt;i&gt;VS Team System&lt;/i&gt; experience to our team.&lt;br&gt;&lt;ul&gt;&lt;li&gt;Sept 18: Neno Loje - Full Day Tutorial on &lt;b&gt;Team Development with Visual Studio 2005 Team System&lt;/b&gt;&lt;/li&gt;&lt;li&gt;Sept 19&lt;/li&gt;&lt;ul&gt;&lt;li&gt;10:15-11:30 - Neno Loje - &lt;b&gt;Visual Studio 2005 Team System&lt;/b&gt;&lt;/li&gt;&lt;li&gt;10:15-11:30 - Ingo Rammer - &lt;b&gt;Hardcore Production Debugging&lt;/b&gt;&lt;/li&gt;&lt;li&gt;14:15-15:30 - Christian Nagel - &lt;b&gt;C++/CLI&lt;/b&gt;&lt;/li&gt;&lt;li&gt;17:15-18:35 - Christian Nagel - &lt;b&gt;System.Transactions&lt;/b&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;Sept 20&lt;/li&gt;&lt;ul&gt;&lt;li&gt;10:15-11:30 - Christian Weyer - &lt;b&gt;Windows Communication Foundation: Think First, Speak Later&lt;br&gt;&lt;/b&gt;&lt;/li&gt;&lt;li&gt;11:45-13:00 - Christian Weyer - &lt;b&gt;Windows Workflow Foundation: Because Workflow is Everywhere&lt;/b&gt;&lt;/li&gt;&lt;li&gt;11:45-13:00 - Ingo Rammer - &lt;b&gt;The Smart Client Software Factory&lt;/b&gt;&lt;br&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;Sept 21: Christian Weyer, Ingo Rammer - Full Day Tutorial on &lt;b&gt;Windows Workflow Foundation&lt;br&gt;&lt;/b&gt;&lt;/li&gt;&lt;/ul&gt;It's going to be fun - see you in a few hours.&lt;br&gt;&lt;img src="http://blogs.thinktecture.com/aggbug.aspx?PostID=414700" width="1" height="1"&gt;</description></item><item><title>Defining KnownTypes in a configuration file</title><link>http://blogs.thinktecture.com/ingo/archive/2006/09/06/414690.aspx</link><pubDate>Wed, 06 Sep 2006 17:03:00 GMT</pubDate><guid isPermaLink="false">ff4ed322-7612-4f43-9d7f-220c081c7cfd:414690</guid><dc:creator>Ingo</dc:creator><slash:comments>3</slash:comments><comments>http://blogs.thinktecture.com/ingo/comments/414690.aspx</comments><wfw:commentRss>http://blogs.thinktecture.com/ingo/commentrss.aspx?PostID=414690</wfw:commentRss><description>&lt;p&gt;WCF's serialization of data contracts supports the transmission of derived types which have not been available when the original application (or just contract) has been built. In the following example, ApplicationExtensionObject is just a placeholder instead of which a derived class should be transferred at runtime. 
&lt;/p&gt;
&lt;pre class="code"&gt;[DataContract]
public class Customer
{
  [DataMember]
  public string Firstname;
  [DataMember]
  public string Lastname;
  [DataMember]
  public Address DefaultDeliveryAddress;
  [DataMember]
  public Address DefaultBillingAddress;

  [DataMember]
&lt;b&gt;  public ApplicationExtensionObject Extension;&lt;/b&gt;
}

[DataContract]
public class ApplicationExtensionObject
{
}
&lt;/pre&gt;
&lt;p&gt;
You would normally accomplish this using the [KnownType] attribute on the field &lt;i&gt;Extension&lt;/i&gt;. But what if you can't do this as the type is not yet known at compile time? Well, for one thing you could use [KnownType(methodName)] to define a method which returns an array of Types at runtime. Another alternative is to use the section  to define the mapping between declared types and known subtypes.&lt;/p&gt;
&lt;p&gt;
In the following snippet, the class ProjectSpecificExtension.CustomerExtension is defined as a valid known subtype of ApplicationExtensionObject for the serializer.
&lt;/p&gt;
&lt;pre class="code"&gt;&amp;lt;configuration &amp;gt;
  &amp;lt;system.runtime.serialization&amp;gt;
    &amp;lt;dataContractSerializer&amp;gt;
      &amp;lt;declaredTypes&amp;gt;
        &amp;lt;add type="Shared.ApplicationExtensionObject, Shared"&amp;gt;
          &amp;lt;knownType type="ProjectSpecificExtension.CustomerExtension, ProjectSpecificExtension" /&amp;gt;
        &amp;lt;/add&amp;gt;
      &amp;lt;/declaredTypes&amp;gt;
    &amp;lt;/dataContractSerializer&amp;gt;
  &amp;lt;/system.runtime.serialization&amp;gt;
  ...
&amp;lt;/configuration&amp;gt;
&lt;/pre&gt;&lt;i&gt;Update: This has actually been documented and is a supported practice. I guess I just made it too much of a habit to look into Reflector instead of searching long enough in the docs ;-)&lt;/i&gt;&lt;img src="http://blogs.thinktecture.com/aggbug.aspx?PostID=414690" width="1" height="1"&gt;</description></item><item><title>Start ServiceHosts for all configured Services</title><link>http://blogs.thinktecture.com/ingo/archive/2006/09/05/414686.aspx</link><pubDate>Tue, 05 Sep 2006 12:47:00 GMT</pubDate><guid isPermaLink="false">ff4ed322-7612-4f43-9d7f-220c081c7cfd:414686</guid><dc:creator>Ingo</dc:creator><slash:comments>5</slash:comments><comments>http://blogs.thinktecture.com/ingo/comments/414686.aspx</comments><wfw:commentRss>http://blogs.thinktecture.com/ingo/commentrss.aspx?PostID=414686</wfw:commentRss><description>&lt;i&gt;Important Update: The originally presented code only works if the service is defined in the same assembly which hosts the service (because the name="" attribute in &amp;lt;service&amp;gt; may not contain the assembly name of the service). See at the end of the article for a slightly different version which works in all cases --- but which involves adding a second config file.&lt;br&gt;&lt;/i&gt;&lt;br&gt;As WCF has reached RC1 stage, I find myself cleaning up a few bits of older WCF code. While playing around with it, I always found myself having to start more and more ServiceHosts for different configurations. The following snippet iterates over all &amp;lt;service&amp;gt; entries in configuration/system.serviceModel and opens a ServiceHost for each of them.&lt;br&gt;&lt;br&gt;&lt;i&gt;Update: Added code to close all services.&lt;br&gt;&lt;/i&gt;&lt;br&gt;&lt;b&gt;&lt;font face="Courier New"&gt;using System;&lt;br&gt;using System.Collections.Generic;&lt;br&gt;using System.Reflection;&lt;br&gt;using System.Configuration;&lt;br&gt;using System.ServiceModel.Configuration;&lt;br&gt;using System.ServiceModel;&lt;br&gt;&lt;br&gt;public class ServiceHostGroup&lt;br&gt;{&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; static List&amp;lt;ServiceHost&amp;gt; _hosts = new List&amp;lt;ServiceHost&amp;gt;();&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private static void OpenHost(Type t)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ServiceHost hst = new ServiceHost(t);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; hst.Open();&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _hosts.Add(hst);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public static void StartAllConfiguredServices()&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Configuration conf = &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ConfigurationManager.OpenExeConfiguration(Assembly.GetEntryAssembly().Location);&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ServiceModelSectionGroup svcmod = &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; (ServiceModelSectionGroup)conf.GetSectionGroup("system.serviceModel");&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; foreach (ServiceElement el in svcmod.Services.Services)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Type svcType = Type.GetType(el.Name);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (svcType == null) &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; throw new Exception("Invalid Service Type " + el.Name + " in configuration file.");&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; OpenHost(svcType);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public static void CloseAllServices()&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; foreach (ServiceHost hst in _hosts)&lt;br&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp; hst.Close();&lt;br&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;}&lt;br&gt;&lt;/font&gt;&lt;/b&gt;&lt;br&gt;As mentioned above, I have in the meantime learned (after long and hard fighting against the "this service has no non-metadata endpoints"-exception), that the name="" attribute in &amp;lt;service&amp;gt; must not contain an assembly name. I guess I have been too used to Remoting configuration files after all ;-). To still get dynamic service configuration without code changes, I've added a second configuration file called services.xml and changed the code for ServiceHostGroup to the following:&lt;br&gt;&lt;br&gt;&lt;i&gt;Services.XML:&lt;br&gt;&lt;/i&gt;&lt;b&gt;&lt;font color="#000000" face="Courier New"&gt;&lt;br&gt;&amp;lt;configuredServices&amp;gt;&lt;br&gt;&amp;nbsp; &amp;lt;service type="ServiceImplementation.ArticleService, ServiceImplementation" /&amp;gt;&lt;br&gt;&amp;lt;/configuredServices&amp;gt;&lt;/font&gt;&lt;/b&gt;&lt;br&gt;&lt;br&gt;&lt;i&gt;ServiceHostBase.cs:&lt;br&gt;&lt;/i&gt;&lt;br&gt;&lt;font face="Courier New"&gt;&lt;b&gt;using System;&lt;br&gt;using System.Collections.Generic;&lt;br&gt;using System.Reflection;&lt;br&gt;using System.Configuration;&lt;br&gt;using System.ServiceModel.Configuration;&lt;br&gt;using System.ServiceModel;&lt;br&gt;using System.Xml;&lt;br&gt;using System.Xml.Serialization;&lt;br&gt;using System.IO;&lt;br&gt;&lt;br&gt;public class ServiceHostGroup&lt;br&gt;{&lt;br&gt;&amp;nbsp; static List&amp;lt;ServiceHost&amp;gt; _hosts = new List&amp;lt;ServiceHost&amp;gt;();&lt;br&gt;&lt;br&gt;&amp;nbsp; private static void OpenHost(Type t)&lt;br&gt;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ServiceHost hst = new ServiceHost(t);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Type ty = hst.Description.ServiceType;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; hst.Open();&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; _hosts.Add(hst);&lt;br&gt;&amp;nbsp; }&lt;br&gt;&lt;br&gt;&amp;nbsp; public static void StartAllConfiguredServices()&lt;br&gt;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ConfiguredServices services = ConfiguredServices.LoadFromFile("services.xml");&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; foreach (ConfiguredService svc in services.Services)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Type svcType = Type.GetType(svc.Type);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (svcType == null) throw new Exception("Invalid Service Type " + svc.Type + " in configuration file.");&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; OpenHost(svcType);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp; }&lt;br&gt;&lt;br&gt;&amp;nbsp; public static void CloseAllServices()&lt;br&gt;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; foreach (ServiceHost hst in _hosts)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; hst.Close();&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp; }&lt;br&gt;}&lt;br&gt;&lt;br&gt;[XmlRoot("configuredServices")]&lt;br&gt;public class ConfiguredServices&lt;br&gt;{&lt;br&gt;&amp;nbsp; public static ConfiguredServices LoadFromFile(string filename)&lt;br&gt;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (!File.Exists(filename)) return new ConfiguredServices();&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; XmlSerializer ser = new XmlSerializer(typeof(ConfiguredServices));&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; using (FileStream fs = File.OpenRead(filename))&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return (ConfiguredServices) ser.Deserialize(fs);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp; }&lt;br&gt;&lt;br&gt;&amp;nbsp; [XmlElement("service", typeof(ConfiguredService))]&lt;br&gt;&amp;nbsp; public List&amp;lt;ConfiguredService&amp;gt; Services = new List&amp;lt;ConfiguredService&amp;gt;();&lt;br&gt;}&lt;br&gt;&lt;br&gt;public class ConfiguredService&lt;br&gt;{&lt;br&gt;&amp;nbsp; [XmlAttribute("type")]&lt;br&gt;&amp;nbsp; public string Type;&lt;br&gt;}&lt;/b&gt;&lt;/font&gt;&lt;br&gt;&lt;img src="http://blogs.thinktecture.com/aggbug.aspx?PostID=414686" width="1" height="1"&gt;</description></item><item><title>WCF server startup slow on W2K3 in VM</title><link>http://blogs.thinktecture.com/ingo/archive/2006/09/04/414684.aspx</link><pubDate>Mon, 04 Sep 2006 19:20:00 GMT</pubDate><guid isPermaLink="false">ff4ed322-7612-4f43-9d7f-220c081c7cfd:414684</guid><dc:creator>Ingo</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.thinktecture.com/ingo/comments/414684.aspx</comments><wfw:commentRss>http://blogs.thinktecture.com/ingo/commentrss.aspx?PostID=414684</wfw:commentRss><description>Just a quick and unrelated tip: If you - like I'm doing it right now - run a WCF server in a Virtual Machine running W2K3 Server and your VM is supposed to be standalone and not part of domain you might experience a delay when a WCF server application is starting. When looking at the issue with &lt;a href="http://www.wireshark.org"&gt;Wireshark/Ethereal&lt;/a&gt; (yes, I do what I preach and a Network Sniffer really is one of the first things I use when I experience some kind of unexpected delay ;-)) I noticed that the machine is broadcasting eight Netbios name service queries on its internal subnet to find a domain controller. These queries time out after about eight seconds, but I really didn't want to wait that long.&lt;br&gt;&lt;br&gt;I'm sure that there are dozens of ways around it, but I simply converted my standalone W2K3 VM to a standalone Domain Controller. Startup time decreased from 8 seconds to less than one second for each time I hit F5 in Visual Studio.&lt;br&gt;&lt;img src="http://blogs.thinktecture.com/aggbug.aspx?PostID=414684" width="1" height="1"&gt;</description></item><item><title>Coming to Brussels on September 25</title><link>http://blogs.thinktecture.com/ingo/archive/2006/08/15/414676.aspx</link><pubDate>Tue, 15 Aug 2006 04:58:00 GMT</pubDate><guid isPermaLink="false">ff4ed322-7612-4f43-9d7f-220c081c7cfd:414676</guid><dc:creator>Ingo</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.thinktecture.com/ingo/comments/414676.aspx</comments><wfw:commentRss>http://blogs.thinktecture.com/ingo/commentrss.aspx?PostID=414676</wfw:commentRss><description>&lt;p&gt;
  As David has &lt;a href="http://blogs.msdn.com/davbosch/archive/2006/08/10/694371.aspx"&gt;
  already blogged&lt;/a&gt;, I will be back in Brussels on September 25. I think that's great as I really like the city
  and wasn't able to make it to the last DevDays there.
&lt;/p&gt;
&lt;p&gt;
  Microsoft is hosting &lt;em&gt;(for free!)&lt;/em&gt; a &lt;a href="http://www.microsoft.com/belux/msdn/nl/events/2006/net30.mspx"&gt;
full day on .NET Framework 3.0&lt;/a&gt; in which &lt;a href= "http://blog.u2u.info/DottextWeb/peter/"&gt;Peter Himschoot&lt;/a&gt; will present on Windows Presentation Foundation and
  CardSpace, and I'll focus on Windows Communication Foundation and Workflow Foundation. It's going to be fun.
  (And: You can still vote for the session contents!)
&lt;/p&gt;&lt;img src="http://blogs.thinktecture.com/aggbug.aspx?PostID=414676" width="1" height="1"&gt;</description></item><item><title>Who is blocking that Mutex? - Fun with WinDbg, CDB and KD</title><link>http://blogs.thinktecture.com/ingo/archive/2006/08/05/414674.aspx</link><pubDate>Sat, 05 Aug 2006 09:31:00 GMT</pubDate><guid isPermaLink="false">ff4ed322-7612-4f43-9d7f-220c081c7cfd:414674</guid><dc:creator>Ingo</dc:creator><slash:comments>4</slash:comments><comments>http://blogs.thinktecture.com/ingo/comments/414674.aspx</comments><wfw:commentRss>http://blogs.thinktecture.com/ingo/commentrss.aspx?PostID=414674</wfw:commentRss><description>&lt;p&gt;I'm currently toying with the idea of creating a small frontend to SOS.DLL
(CDB/WinDbg) and KD. This frontend should simplify some production debugging
tasks based on crash dumps. (In my prototype, I'm already happily clicking
myself through managed code threads, callstacks, parameters, locals and
browsing objects' contents just like in Visual Studio, but solely based on
crash dumps.) &lt;/p&gt;

&lt;p&gt;A lot of debugging work is in general based on identifying a set of rather
common issues. But even if you are tracking down a very common issue, it's
still a tough call to work through 25 managed code callstacks to find out - for
example - why a certain thread might be blocking a number of other threads.
This was the rationale behind some of the features I'm thinking about implementing
in the debugging frontend tool: to simplify and automate some manual tasks. But
this tool is not (yet) ready for writing about, so lets look at the manual
process for finding out whos blocking your thread.&lt;/p&gt;

&lt;p&gt;For the analysis of thread&amp;nbsp;blocks&amp;nbsp;based on WaitHandles,&amp;nbsp;I've
found two kinds of possible solutions: one which is not 100% deterministic but
works on crash dumps (but only for named synchronization objects) and another
one which is deterministic but only works on the live system with a kernel debugger.
I'll show you both approaches in this post.&lt;/p&gt;

&lt;h2&gt;First Approach  - User Mode only, but works on Dumps &lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Note: This approach is not deterministic and not accurate but based on
the automated equivalent of trial and error in the form of &lt;/em&gt;&lt;code&gt;&lt;i&gt;&lt;span&gt;!DumpStackObjects&lt;/span&gt;&lt;/i&gt;&lt;/code&gt;&lt;em&gt;. It's
essentially based on looking for WaitHandle references on a callstack and
similar means to get the identifier of a named synchronization object. The only
good news is that it works on dumps generated by ADPlus (and of course on live
systems as well).&lt;/em&gt; &lt;/p&gt;

&lt;p&gt;Ok. Let's get startet. Suppose you have a process in which several threads
end up blocking others for periods longer than you would expect and you
basically want to know which threads block on resources held by which other
threads. You've created a -hang dump with ADPlus and are ready to examine the
dump in WinDbg or CDB.&lt;/p&gt;

&lt;p&gt;First, you will need to find out which threads are actually waiting for
something. To do this, you first load SOS.DLL and then look at the states of your
managed threads:&lt;/p&gt;

&lt;div class="Code"&gt;
	&lt;pre class="Code"&gt;&lt;span&gt;0:013&amp;gt; &lt;/span&gt;&lt;span&gt;&lt;b&gt;.loadby sos mscorwks&lt;/b&gt;     &lt;/span&gt;&lt;span&gt;// load the extension sos.dll in directory of mscorwks&lt;/span&gt;&lt;span&gt;
0:013&amp;gt; &lt;/span&gt;&lt;span&gt;&lt;b&gt;!threads&lt;/b&gt;                   &lt;/span&gt;&lt;span&gt;// list all managed threads
&lt;/span&gt;&lt;span&gt;ThreadCount: 12
UnstartedThread: 0
BackgroundThread: 1
PendingThread: 0
DeadThread: 0
Hosted Runtime: no
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;PreEmptive   GC Alloc           Lock
       ID OSID ThreadOBJ   State     GC       Context       Domain   Count APT Exception
&lt;/span&gt;   0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;1&amp;nbsp;&amp;nbsp;b70 00180fd0   200a020 Enabled&amp;nbsp;&amp;nbsp;00000000:00000000 0014c100     0 MTA
&lt;span&gt;   2&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;2 1b54 00152480&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;b220 Enabled&amp;nbsp;&amp;nbsp;00000000:00000000 0014c100     0 MTA (Finalizer)
&lt;/span&gt;   3&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;3 1ba0 0019a1c0   200b020 Enabled&amp;nbsp;&amp;nbsp;00000000:00000000 0014c100     0 MTA
   4&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;4 1f9c 0019c138   200b020 Enabled&amp;nbsp;&amp;nbsp;00000000:00000000 0014c100     0 MTA
   5&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;5&amp;nbsp;&amp;nbsp;210 0019cd18   200b020 Enabled&amp;nbsp;&amp;nbsp;00000000:00000000 0014c100     0 MTA
   6&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;6 13e0 0019d8d0   200b020 Enabled&amp;nbsp;&amp;nbsp;00000000:00000000 0014c100     0 MTA
   &lt;span&gt;7&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;7 17e0 0019e488   200b020 Enabled  00000000:00000000 0014c100     0 MTA
   &lt;/span&gt;8&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;8 1204 0019f040   200b020 Enabled&amp;nbsp;&amp;nbsp;00000000:00000000 0014c100     0 MTA
&lt;span&gt;   9&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;9 1ec0 0019fbf8      b020 Disabled 00000000:00000000 0014c100     0 MTA
&amp;nbsp;&amp;nbsp;10&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;a 1a48 001a07b0      b020 Disabled 00000000:00000000 0014c100     0 MTA
&lt;/span&gt;&amp;nbsp;&amp;nbsp;11&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;b 1558 001a1368   200b020 Enabled&amp;nbsp;&amp;nbsp;00000000:00000000 0014c100     0 MTA
&amp;nbsp;&amp;nbsp;12&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;c 1d88 001a1f20   200b020 Enabled&amp;nbsp;&amp;nbsp;00000000:00000000 0014c100     0 MTA&lt;/pre&gt;
	&lt;p&gt;The threads with state 200a020 are currently waiting. As this does not
necessarily mean that they are waiting for a WaitHandle (they could also just
have called Thread.Sleep()), you now also need to find out which of these
blocked threads are actually blocking on a WaitHandle.&lt;/p&gt;

&lt;p&gt;To do this, you will have to look at the top managed code stackframe in each
of the blocked threads. &lt;i&gt;(Please note: You have to specify the native thread
ID for the next command. This ID is contained in the first column of !threads, and
is not the CLR thread id contained in the second column!)&lt;/i&gt;&lt;/p&gt;

	&lt;pre class="Code"&gt;&lt;span&gt;0:007&amp;gt; &lt;/span&gt;&lt;span&gt;~0e !clrstack&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span&gt;// list the managed call stack of thread 0 (CLR thread #1)
&lt;/span&gt;&lt;span&gt;OS Thread Id: 0xb70 (0)
ESP       EIP
0012f420 7c90eb94 [HelperMethodFrame: 0012f420] System.Threading.Thread.SleepInternal(Int32)
0012f474 793d80f5 System.Threading.Thread.Sleep(Int32)
0012f478 00ca00fb ResourceLock.Program.Main(System.String[])
0012f69c 79e88f63 [GCFrame: 0012f69c]&lt;/span&gt;&lt;/pre&gt;
	&lt;p&gt;As you can see in this first example, the specified thread does not block on
a WaitHandle, so let's continue our search. &lt;i&gt;(Note: instead of manually using
~&amp;lt;THREAD_NUMBER&amp;gt;e !clrstack  for each thread, you could also call ~*e
!clrstack, do dump the complete managed code callstacks for all threads.)&lt;/i&gt;&lt;/p&gt;
	&lt;pre class="Code"&gt;0:007&amp;gt; &lt;span&gt;~7e !clrstack           &lt;/span&gt;&lt;span&gt;// list the managed call stack of thread 7 (also CLR thread #7)
&lt;/span&gt;&lt;span&gt;OS Thread Id: 0x17e0 (7)
ESP       EIP
011cf588 7c90eb94 [HelperMethodFrame_1OBJ: 011cf588] System.Threading.WaitHandle.WaitOneNative(Microsoft.Win32.SafeHandles.SafeWaitHandle, U
Int32, Boolean, Boolean)
011cf634 793d424e System.Threading.WaitHandle.WaitOne(Int64, Boolean)
011cf64c 793d4193 System.Threading.WaitHandle.WaitOne(Int32, Boolean)
011cf65c 793d420e System.Threading.WaitHandle.WaitOne()
011cf660 00ca0250 ResourceLock.Program.ThreadProc()
011cf6b4 793d7a7b System.Threading.ThreadHelper.ThreadStart_Context(System.Object)
011cf6bc 793683dd System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
011cf6d4 793d7b5c System.Threading.ThreadHelper.ThreadStart()
011cf8f8 79e88f63 [GCFrame: 011cf8f8]&lt;/span&gt;&lt;/pre&gt;
	&lt;p&gt;Here, the top level call stack elements contain calls to
WaitHandle.WaitOne() or WaitOneNative(). This thread is currently waiting for a
synchronization object.&lt;/p&gt;

&lt;p&gt;To retrieve details of the underlying sync object, you first have to look at
the unmanaged callstack for the same thread. You will usually send a command
like "kb 5" to the debugger after selecting the current thread with
~7 s. &lt;/p&gt;

	&lt;pre class="Code"&gt;&lt;span&gt;0:007&amp;gt; &lt;/span&gt;&lt;span&gt;~7 s&lt;/span&gt;&lt;span&gt;                   // select thread 7 if its not the current thread
&lt;/span&gt;&lt;span&gt;eax=00000000 ebx=011cf350 ecx=79690098 edx=79690048 esi=00000000 edi=7ffde000
eip=7c90eb94 esp=011cf328 ebp=011cf3c4 iopl=0         nv up ei pl nz na po nc
&lt;/span&gt;&lt;span&gt;cs=001b&amp;nbsp;&amp;nbsp;ss=0023 ds=0023&amp;nbsp;&amp;nbsp;es=0023&amp;nbsp;&amp;nbsp;fs=003b&amp;nbsp;&amp;nbsp;gs=0000             efl=00000202
&lt;/span&gt;&lt;span&gt;ntdll!KiFastSystemCallRet:
7c90eb94 c3&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ret
0:007&amp;gt; &lt;/span&gt;&lt;span&gt;kb 5 &lt;/span&gt;&lt;span&gt;                  // print five stack frames
&lt;/span&gt;&lt;span&gt;ChildEBP RetAddr&amp;nbsp;&amp;nbsp;Args to Child
&lt;/span&gt;&lt;span&gt;011cf324 7c90e9ab 7c8094f2 00000001 011cf350 ntdll!KiFastSystemCallRet
&lt;/span&gt;&lt;span&gt;011cf328 7c8094f2 00000001 011cf350 00000000 ntdll!ZwWaitForMultipleObjects+0xc
011cf3c4 79f8ead4 00000001 011cf614 00000001 KERNEL32!WaitForMultipleObjectsEx+0x12c
011cf42c 79f17522 00000001 011cf614 00000001 mscorwks!WaitForMultipleObjectsEx_SO_TOLERANT+0x6f
011cf44c 79f17493 00000001 011cf614 00000001 mscorwks!Thread::DoAppropriateAptStateWait+0x3c&amp;nbsp;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;Please note: This output is what youll receive if you have debug symbols
configured correctly. While its definitely not as nice as the one with
symbols, you can still get the same information (minus the method names) even
if you do not have debug symbols installed:&lt;/p&gt;

	&lt;pre class="Code"&gt;&lt;span&gt;0:007&amp;gt; &lt;/span&gt;&lt;span&gt;kb 5&lt;/span&gt;&lt;span&gt;                   // print five stack frames
&lt;/span&gt;&lt;span&gt;ChildEBP RetAddr&amp;nbsp;&amp;nbsp;Args to Child
WARNING: Stack unwind information not available. Following frames may be wrong.
011cf3c4 79f8ead4 00000001 011cf614 00000001 ntdll!KiFastSystemCallRet
011cf42c 79f17522 00000001 011cf614 00000001 mscorwks!StrongNameFreeBuffer+0x57fc
011cf44c 79f17493 00000001 011cf614 00000001 mscorwks!CreateAssemblyCache+0x9474
011cf4d0 79f1732f 00000001 011cf614 00000001 mscorwks!CreateAssemblyCache+0x93e5
011cf520 7a07b49c 00000001 011cf614 00000001 mscorwks!CreateAssemblyCache+0x9281&lt;/span&gt;&lt;/pre&gt;
	&lt;p&gt;Here, I'll ignore the first three lines in any case, no matter if we have
symbols or not. The next line is usually a call to WaitForMultipleObjectEx or a
comparable function. This function is defined like this:&lt;/p&gt;
	&lt;pre class="Code"&gt;&lt;span&gt;DWORD WaitForMultipleObjectsEx(
&amp;nbsp;&amp;nbsp;DWORD &lt;i&gt;&lt;span class="MsoHyperlink"&gt;&lt;span&gt;nCount&lt;/span&gt;&lt;/span&gt;&lt;/i&gt;,
&amp;nbsp;&amp;nbsp;const HANDLE* &lt;i&gt;&lt;span class="MsoHyperlink"&gt;&lt;span&gt;lpHandles&lt;/span&gt;&lt;/span&gt;&lt;/i&gt;,
&amp;nbsp;&amp;nbsp;BOOL &lt;i&gt;&lt;span class="MsoHyperlink"&gt;&lt;span&gt;bWaitAll&lt;/span&gt;&lt;/span&gt;&lt;/i&gt;,
&amp;nbsp;&amp;nbsp;DWORD &lt;i&gt;&lt;span class="MsoHyperlink"&gt;&lt;span&gt;dwMilliseconds&lt;/span&gt;&lt;/span&gt;&lt;/i&gt;,
&amp;nbsp;&amp;nbsp;BOOL &lt;i&gt;&lt;span class="MsoHyperlink"&gt;&lt;span&gt;bAlertable
&lt;/span&gt;&lt;/span&gt;&lt;/i&gt;);&lt;/span&gt;&lt;/pre&gt;
	&lt;p&gt;In the third, fourth and fifth field of the output of kb 5, we can get the
first three arguments to the method. We therefore know that nCount = 1 and
lpHandles =  011cf614. This means that the .NET Framework has passed an array
of handles which contains 1 (nCount) entry and starts at the location 011cf614
(lpHandles) to WaitForMultipleObjectsEx.&lt;/p&gt;

&lt;p&gt;You can then call &lt;code&gt;&lt;span&gt;"dd
&amp;lt;address&amp;gt; L&amp;lt;number_of_handles&amp;gt;"&lt;/span&gt;&lt;/code&gt; (for example &lt;code&gt;&lt;span&gt;"dd 011cf614 L00000001"&lt;/span&gt;&lt;/code&gt;) to
the debugger to generate a memory dump to retrieve the list of handles. &lt;/p&gt;

	&lt;pre class="Code"&gt;&lt;span&gt;0:007&amp;gt; &lt;/span&gt;&lt;span&gt;dd 011cf614 L1     &lt;/span&gt;&lt;span&gt;// dump 1 dword at location 011cf614
&lt;/span&gt;&lt;span&gt;011cf614&amp;nbsp;&amp;nbsp;00000684&lt;/span&gt;&lt;/pre&gt;
	&lt;p&gt;In this command, the first field in each line contains the memory address
and the subsequent fields (only one in our case) contain the handle to the
object you are waiting for. &lt;/p&gt;

&lt;p&gt;For each handle, you can then then call &lt;code&gt;&lt;span&gt;"!handle
&amp;lt;handle&amp;gt; f"&lt;/span&gt;&lt;/code&gt;, for example &lt;code&gt;&lt;span&gt;"handle 00000684 f"&lt;/span&gt;&lt;/code&gt; to retrieve handle
information: &lt;/p&gt;

	&lt;pre class="Code"&gt;&lt;code&gt;&lt;span&gt;0:007&amp;gt; &lt;/span&gt;&lt;span&gt;!handle 00000684 f&lt;/span&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// dump detailed information (flags = f) for handle 684
&lt;/span&gt;&lt;span&gt;Handle 684
&amp;nbsp;&amp;nbsp;Type&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Mutant
&amp;nbsp;&amp;nbsp;Attributes&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;0
&amp;nbsp;&amp;nbsp;GrantedAccess 0x1f0001:
         Delete,ReadControl,WriteDac,WriteOwner,Synch
         QueryState
&amp;nbsp;&amp;nbsp;HandleCount   4
&amp;nbsp;&amp;nbsp;PointerCount&amp;nbsp;&amp;nbsp;8
&lt;/span&gt;&lt;b&gt;  Name         \BaseNamedObjects\{1CA3A6E4-68E7-4847-9602-5669BC40D01E}
&lt;/b&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;Object Specific Information
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Mutex is Owned&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
	&lt;p&gt;In this case, you now know that the thread is waiting for a Mutex (&lt;em&gt;Mutant&lt;/em&gt;
is the kernel-level name for a &lt;em&gt;Mutex&lt;/em&gt;) which has been named
"{1CA3A6E4-68E7-4847-9602-5669BC40D01E}". &lt;/p&gt;

&lt;p&gt;The next step is to find out who currently owns this mutex. This would be
relatively straightforward in a live debug as we could use a kernel debugger to
identify the owning thread (which I'll explain later). In a crash dump however, we
are somewhat limited as we have to hunt for this information in a
trial-and-error way. We are also limited to owner threads in the same process 
if the named mutex is owned by a thread in another process, we won't be able to
get there with our single-process memory dump.&lt;/p&gt;

&lt;p&gt;This trial-and-error information retrieval comes in the form of &lt;i&gt;!DumpStackObjects&lt;/i&gt;
(which can be abbreviated to &lt;i&gt;!dso&lt;/i&gt;), an extension command which walks the
stack of the selected thread and checks if each value it finds on the stack &lt;i&gt;could&lt;/i&gt;
be a managed object. &lt;/p&gt;

	&lt;pre class="Code"&gt;&lt;span&gt;0:007&amp;gt; &lt;/span&gt;&lt;span&gt;~0e !dso&lt;/span&gt;&lt;span&gt;                     // dump stack objects for thread #0
&lt;/span&gt;&lt;span&gt;OS Thread Id: 0xb70 (0)
ESP/REG&amp;nbsp;&amp;nbsp;Object   Name
0012f408 01273450 System.IO.StreamWriter
0012f428 01274768 System.Char[]
0012f478 01271b38 System.Object[]&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(System.String[])
0012f534 01271b38 System.Object[]&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(System.String[])
0012f6e0 01271b38 System.Object[]&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(System.String[])
0012f708 01271b38 System.Object[]&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(System.String[])&lt;/span&gt;&lt;/pre&gt;
	&lt;p&gt;Theres not a lot going on in this thread. Certainly no Mutex here, let's go
on:&lt;/p&gt;
	&lt;pre class="Code"&gt;&lt;span&gt;0:007&amp;gt; &lt;/span&gt;&lt;span&gt;~4e !dso &lt;/span&gt;&lt;span&gt;                    // dump stack objects for thread #4
&lt;/span&gt;&lt;span&gt;OS Thread Id: 0x1f9c (4)
ESP/REG&amp;nbsp;&amp;nbsp;Object   Name
00ecf748 01273b30 System.String&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Thread 4 sleeping
00ecf770 01273450 System.IO.StreamWriter
00ecf790 01273b64 System.Char[]
00ecf804 01273a40 System.Threading.ThreadStart
00ecf808 01273a40 System.Threading.ThreadStart
00ecf80c 01273a94 System.Threading.ThreadHelper
00ecf814 01271db8 System.String&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Thread
00ecf818 01273a94 System.Threading.ThreadHelper
00ecf81c 01271d98 System.Threading.ContextCallback
00ecf820 01273a94 System.Threading.ThreadHelper
00ecf82c 01273a94 System.Threading.ThreadHelper
00ecf834 01273ac8 System.Threading.ExecutionContext
00ecf844 01273ac8 System.Threading.ExecutionContext
00ecf848 01273a94 System.Threading.ThreadHelper
00ecf850 01273a94 System.Threading.ThreadHelper
00ecf914 01273aa8 System.Threading.ThreadStart
00ecfac0 01273aa8 System.Threading.ThreadStart
00ecfad0 01273aa8 System.Threading.ThreadStart&lt;/span&gt;&lt;/pre&gt;
	&lt;p&gt;Thread #4 looks more interesting but contains no reference to any
synchronization object, let's continue again:&lt;/p&gt;
	&lt;pre class="Code"&gt;&lt;span&gt;0:007&amp;gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;~3e !dso &lt;/span&gt;&lt;span&gt;                    // dump stack objects for thread #3
&lt;/span&gt;&lt;span&gt;OS Thread Id: 0x1ba0 (3)
ESP/REG&amp;nbsp;&amp;nbsp;Object   Name
00daf7c8 012739d8 System.String&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Thread 3 sleeping
00daf7f0 01273450 System.IO.StreamWriter
00daf810 01273a0c System.Char[]
&lt;/span&gt;&lt;i&gt;00daf880 0127383c System.Threading.Mutex
&lt;/i&gt;&lt;span&gt;00daf884 01271db8 System.String&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Thread
00daf888 01271db8 System.String&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Thread
00daf88c 01271db8 System.String&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Thread
00daf898 01271cb8 System.Threading.ThreadHelper
00daf89c 01271d98 System.Threading.ContextCallback
00daf8a0 01271cb8 System.Threading.ThreadHelper
00daf8ac 01271cb8 System.Threading.ThreadHelper
00daf8b4 01271d2c System.Threading.ExecutionContext
00daf8c4 01271d2c System.Threading.ExecutionContext
00daf8c8 01271cb8 System.Threading.ThreadHelper
00daf8d0 01271cb8 System.Threading.ThreadHelper
00daf994 01271ccc System.Threading.ThreadStart
00dafb40 01271ccc System.Threading.ThreadStart
00dafb50 01271ccc System.Threading.ThreadStart&lt;/span&gt;&lt;/pre&gt;
	&lt;p&gt;At first glance, thread #3 looks innocent too. Only when examining it more
closely, you'll find a Mutex as the fourth stack object. (Of course, this is
now total guesswork as we don't know if the thread ever really acquired the
mutex or if it is just looking at it. The thread might also have already released
the mutex as well  but I don't know if we can find an answer to these
questions without looking at kernel memory.)&lt;/p&gt;

&lt;p&gt;First, lets look if the method acquires a mutex &lt;i&gt;at all&lt;/i&gt;. To do this,
we first need to find out the method which owns this section of the stack. To
do this, we take the value of ESP for our Mutex (which is the address on the
stack which references the mutex) which is &lt;i&gt;00daf880&lt;/i&gt; in our case and compare
it to the managed code stack dump of the same thread:&lt;/p&gt;

	&lt;pre class="Code"&gt;&lt;span&gt;0:007&amp;gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;~3 s &lt;/span&gt;&lt;span&gt;                  // select thread #3
&lt;/span&gt;&lt;span&gt;eax=7a38cf40 ebx=00000000 ecx=79ed75c0 edx=fbffffff esi=00000000 edi=00daf700
eip=7c90eb94 esp=00daf6d0 ebp=00daf728 iopl=0         nv up ei pl nz na pe nc
&lt;/span&gt;&lt;span&gt;cs=001b&amp;nbsp;&amp;nbsp;ss=0023 ds=0023&amp;nbsp;&amp;nbsp;es=0023&amp;nbsp;&amp;nbsp;fs=003b&amp;nbsp;&amp;nbsp;gs=0000             efl=00000206
&lt;/span&gt;&lt;span&gt;ntdll!KiFastSystemCallRet:
7c90eb94 c3&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ret
0:003&amp;gt; &lt;/span&gt;&lt;span&gt;!clrstack&lt;/span&gt;&lt;span&gt;               // dump the managed code stack for this method
&lt;/span&gt;&lt;span&gt;OS Thread Id: 0x1ba0 (3)
ESP       EIP
00daf808 7c90eb94 [HelperMethodFrame: 00daf808] System.Threading.Thread.SleepInternal(Int32)
00daf85c 793d80f5 System.Threading.Thread.Sleep(Int32)
&lt;/span&gt;00daf860 00ca02c3 ResourceLock.Program.ThreadProc()
&lt;span&gt;00daf8b4 793d7a7b System.Threading.ThreadHelper.ThreadStart_Context(System.Object)
00daf8bc 793683dd System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
00daf8d4 793d7b5c System.Threading.ThreadHelper.ThreadStart()
00dafaf8 79e88f63 [GCFrame: 00dafaf8]&lt;/span&gt;&lt;/pre&gt;
	&lt;p&gt;In this stack dump, you can see that the stack address of the reference to
the mutex (00daf880) lies between the third and the fourth frame's ESP. You can
deduce that the object is created in the third frame, in the method ResourceLock.Program.ThreadProc().
	&lt;/p&gt;

&lt;p&gt;To verify this, you can have a look at the IL code of this method. First you
need to convert the Instruction Pointer (IP) to a method description. The IP is
&lt;i&gt;00ca02c3&lt;/i&gt; according to the output of !clrstack (second field in the stack
frame for ThreadProc()). &lt;/p&gt;

	&lt;pre class="Code"&gt;&lt;span&gt;0:003&amp;gt; &lt;/span&gt;&lt;span&gt;&lt;b&gt;!IP2MD 00ca02c3&lt;/b&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span&gt;// convert an instruction pointer (IP) to a method description (MethodDesc)
&lt;/span&gt;&lt;i&gt;MethodDesc: 00912ff8
&lt;/i&gt;&lt;span&gt;Method Name: ResourceLock.Program.ThreadProc()
Class: 009112c4
MethodTable: 00913010
mdToken: 06000003
Module: 00912c14
IsJitted: yes
m_CodeOrIL: 00ca0188&lt;/span&gt;&lt;/pre&gt;
	&lt;p&gt;The resulting MethodDesc is 00912ff8. You can use this a parameter to
!DumpIL to retrieve the IL code of this method:&lt;/p&gt;
	&lt;pre class="Code"&gt;&lt;span&gt;0:003&amp;gt; &lt;/span&gt;&lt;span&gt;!dumpil 00912ff8&lt;/span&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// get the IL code for a method
&lt;/span&gt;&lt;span&gt;ilAddr = 004020b4
IL_0000: nop
IL_0001: call System.Threading.Thread::get_CurrentThread
&amp;nbsp;&amp;nbsp;...
IL_004a: newobj System.Threading.Mutex::.ctor
IL_004f: stloc.2
IL_0050: ldloc.2
IL_0051: callvirt System.Threading.WaitHandle::WaitOne&lt;/span&gt;&lt;/pre&gt;
	&lt;p&gt;IL_0044 to IL_51 roughly translate to the following C# fragment: &lt;/p&gt;
	&lt;pre class="Code"&gt;&lt;span&gt;Mutex mtx = new Mutex (...);
mtx.WaitOne();&lt;/span&gt;&lt;/pre&gt;
	&lt;p&gt;So, yes, the method definitely acquires at least one mutex at one point. But
to find out if the the Mutex we've found on the stack &lt;i&gt;really&lt;/i&gt; references
the same named synchronization object the other thread is blocking on, we need
to examine it more closely. First, let's have a look at the contents of the
mutex by using &lt;i&gt;!DumpObj&lt;/i&gt; (which we abbreviate to &lt;i&gt;!do&lt;/i&gt;).&lt;/p&gt;
	&lt;pre class="Code"&gt;&lt;span&gt;0:003&lt;/span&gt;&amp;gt; &lt;span&gt;!do 0127383c &lt;/span&gt;&lt;span&gt;    // dump the mutex. Address is from ~3e !dso
&lt;/span&gt;&lt;span&gt;Name: System.Threading.Mutex
MethodTable: 7910d018
EEClass: 7910cfa0
Size: 24(0x18) bytes
(C:\WINDOWS\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
Fields:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;MT&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Field   Offset                 Type VT     Attr&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Value Name
790f9c18&amp;nbsp;&amp;nbsp;4000184       4&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.Object&amp;nbsp;&amp;nbsp;0 instance 00000000 __identity
&lt;/span&gt;&lt;i&gt;790fe160&amp;nbsp;&amp;nbsp;40005a6&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;c&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.IntPtr&amp;nbsp;&amp;nbsp;0 instance     1752 waitHandle
&lt;/i&gt;&lt;span&gt;7910cf3c&amp;nbsp;&amp;nbsp;40005a7&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;8 ...es.SafeWaitHandle&amp;nbsp;&amp;nbsp;0 instance 012738d8 safeWaitHandle
79104f64&amp;nbsp;&amp;nbsp;40005a8       10       System.Boolean&amp;nbsp;&amp;nbsp;0 instance&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;1 hasThreadAffinity
790fe160&amp;nbsp;&amp;nbsp;40005a9     984&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.IntPtr&amp;nbsp;&amp;nbsp;0   shared   static InvalidHandle
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;gt;&amp;gt; Domain:Value 0014c100:-1 &amp;lt;&amp;lt;
79104f64&amp;nbsp;&amp;nbsp;40005ee&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;990       System.Boolean&amp;nbsp;&amp;nbsp;0   shared   static dummyBool
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;gt;&amp;gt; Domain:Value 0014c100:NotInit&amp;nbsp;&amp;nbsp;&amp;lt;&amp;lt;
7910d018&amp;nbsp;&amp;nbsp;40005ef&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;14c ...m.Threading.Mutex&amp;nbsp;&amp;nbsp;0   shared   static s_ReservedMutex
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;gt;&amp;gt; Domain:Value 0014c100:NotInit&amp;nbsp;&amp;nbsp;&amp;lt;&amp;lt;&lt;/span&gt;&lt;/pre&gt;
	&lt;p&gt;The second field is called waitHandle and contains the value 1752. This is
the decimal handle to the underlying mutex. Lets convert this to hex (6d8) and
have a look at the handle:&lt;/p&gt;
	&lt;pre class="Code"&gt;&lt;span&gt;0:003&amp;gt; &lt;/span&gt;&lt;span&gt;!handle 6d8 f&lt;/span&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// look at handle 6d8 (decimal 1752)
&lt;/span&gt;&lt;span&gt;Handle 6d8
&amp;nbsp;&amp;nbsp;Type&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Mutant
&amp;nbsp;&amp;nbsp;Attributes&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;0
&amp;nbsp;&amp;nbsp;GrantedAccess 0x1f0001:
         Delete,ReadControl,WriteDac,WriteOwner,Synch
         QueryState
&amp;nbsp;&amp;nbsp;HandleCount   4
&amp;nbsp;&amp;nbsp;PointerCount&amp;nbsp;&amp;nbsp;8
&amp;nbsp;&amp;nbsp;Name         \BaseNamedObjects\{1CA3A6E4-68E7-4847-9602-5669BC40D01E}
&amp;nbsp;&amp;nbsp;Object Specific Information
 &amp;nbsp;&amp;nbsp;&amp;nbsp;Mutex is Owned&lt;/span&gt;&lt;/pre&gt;
	&lt;p&gt;As you can see, thread #3 acquired the mutex with the name {1CA3A6E4-68E7-4847-9602-5669BC40D01E}
using wait handle 6d8, and this is the exact same named mutex which thread #7
is waiting for on wait handle 684. It seems that we got lucky this time and
could find the mutex in our crash dump. Whats left as an exercise is to dump the
!clrstack of thread #3 and examine the top stackframes using !IP2MD and !DumpIL
to find out why the mutex has not been released in time.&lt;/p&gt;

&lt;h2&gt;The Deterministic Second Approach  - or: Now give me my Kernel Debugger!&lt;/h2&gt;

&lt;p&gt;If someone would have told me just two years ago that I'd ever start a
kernel debugger, I wouldn't have believed him: after all, I'm not writing
device drivers and that's all you need KD.EXE for &lt;i&gt;and&lt;/i&gt; it's quite
difficult to setup kernel debugging in the first place, right? Well, turns out
that neither is the case. &lt;/p&gt;

&lt;p&gt;If you only want to examine kernel structures on your local machine, you can
start a kernel debugger as easily as KD.EXE /KL (and it's part of the same
Debugging Tools for Windows package which contains WinDbg and CDB). Theres
no need to setup a second machine and connect the debugger to it or anything
like this. The only really important part is that  contrary to WinDbg and CDB
 you absolutely have to have debug symbols configured correctly for what we
are doing now. Usually its enough to just create a directory like c:\symbols,
set &lt;i&gt;_NT_SYMBOL_PATH&lt;/i&gt; to the matching entry &lt;i&gt;SRV*c:\symbols*http://msdl.microsoft.com/download/symbols
&lt;/i&gt; and start KD. The necessary symbols will be downloaded automatically
behind the scenes whenever they are needed for the first time. (Note that this
also means that KD will block from time to time while it's downloading symbols
on demand.)&lt;/p&gt;

	&lt;pre class="Code"&gt;&lt;span&gt;C:\debug&amp;gt;&lt;/span&gt;&lt;span&gt;set _NT_SYMBOL_PATH=SRV*C:\symbols*&lt;a href="http://msdl.microsoft.com/download/symbols"&gt;http://msdl.microsoft.com/download/symbols&lt;/a&gt;
&lt;/span&gt;&lt;span&gt;&amp;nbsp;
C:\debug&amp;gt;&lt;/span&gt;&lt;span&gt;kd /KL

&lt;/span&gt;&lt;span&gt;Microsoft (R) Windows Debugger Version 6.6.0007.5
Copyright (c) Microsoft Corporation. All rights reserved.

Connected to Windows XP 2600 x86 compatible target, ptr64 FALSE
Symbol search path is: SRV*C:\symbols*&lt;a href="http://msdl.microsoft.com/download/symbols"&gt;http://msdl.microsoft.com/download/symbols&lt;/a&gt;
Executable search path is:
*******************************************************************************
WARNING: Local kernel debugging requires booting with /debug to work optimally.
*******************************************************************************
Windows XP Kernel Version 2600 (Service Pack 2) UP Free x86 compatible
Product: WinNt, suite: TerminalServer SingleUserTS
Built by: 2600.xpsp_sp2_gdr.050301-1519
Kernel base = 0x804d7000 PsLoadedModuleList = 0x8055a420
Debug session time: Sat Aug&amp;nbsp;&amp;nbsp;5 11:19:11.543 2006 (GMT+2)
System Uptime: 6 days 14:14:43.119
lkd&amp;gt;&lt;/span&gt;&lt;/pre&gt;
	&lt;p&gt;Well, allright then. Let's start to hunt for the mutex. And don't forget: &lt;i&gt;you
can run WinDbg/CDB *and* KD at the same time to debug the user-mode and the
kernel-mode parts side by side!&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;First, we need to get information about the process which we are debugging.
The EXE in my example is called ResourceLock.exe, but you can use the !process
command in KD to retrieve the necessary entry point for any process on your
machine: &lt;i&gt;(I'll use red color coding for KD commands and blue color coding
for CDB commands)&lt;/i&gt;&lt;/p&gt;

	&lt;pre class="Code"&gt;&lt;span&gt;lkd&amp;gt; &lt;/span&gt;&lt;span&gt;!process 0 0 ResourceLock.exe&lt;/span&gt;&lt;span&gt;         // retrieve information for all processes running ResourceLock.exe
&lt;/span&gt;&lt;span&gt;PROCESS 8900e020&amp;nbsp;&amp;nbsp;SessionId: 0 Cid: 1cd0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Peb: 7ffde000&amp;nbsp;&amp;nbsp;ParentCid: 12a0
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;DirBase: 0cb83000&amp;nbsp;&amp;nbsp;ObjectTable: e72125c8&amp;nbsp;&amp;nbsp;HandleCount: 122.
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Image: ResourceLock.exe&lt;/span&gt;&lt;/pre&gt;
	&lt;p&gt;The &lt;i&gt;!process&lt;/i&gt; command can also be used to retrieve additional
information. It accepts two numeric parameters: the process address and a list
of flags. If you specify the process address we've retrieved above (8900e020)
and the value 2 for flags, you'll get detailed information about the individual threads and their synchronization objects:&lt;/p&gt;

&lt;p&gt;&lt;b&gt;&lt;i&gt;Important: If you are running WinDbg/CDB and KD side-by-side for the
same process, you must switch WinDbg/CDB in to run mode (F5 or g) to retrieve
this information.&lt;/i&gt;&lt;/b&gt;&lt;/p&gt;

	&lt;pre class="Code"&gt;&lt;span&gt;lkd&amp;gt; &lt;/span&gt;&lt;span&gt;!process 8900e020 2&lt;/span&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// retrieve thread info for process
&lt;/span&gt;&lt;span&gt;PROCESS 8900e020&amp;nbsp;&amp;nbsp;SessionId: 0 Cid: 1cd0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Peb: 7ffde000&amp;nbsp;&amp;nbsp;ParentCid: 12a0
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;DirBase: 0cb83000 ObjectTable: e72125c8&amp;nbsp;&amp;nbsp;HandleCount: 122.
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Image: ResourceLock.exe
&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;THREAD 89285020&amp;nbsp;&amp;nbsp;Cid 1cd0.0b70&amp;nbsp;&amp;nbsp;Teb: 7ffdd000 Win32Thread: e52fe420 WAIT: (DelayExecution) UserMode Alertable
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;89285110 NotificationTimer
&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;THREAD 8a02f280&amp;nbsp;&amp;nbsp;Cid 1cd0.0268&amp;nbsp;&amp;nbsp;Teb: 7ffdc000 Win32Thread: 00000000 WAIT: (UserRequest) UserMode Non-Alertable
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;891da5f8 SynchronizationEvent
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;8a13d6f8 SynchronizationEvent
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;89d50020 SynchronizationEvent
&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;THREAD 88f9fd58&amp;nbsp;&amp;nbsp;Cid 1cd0.1b54&amp;nbsp;&amp;nbsp;Teb: 7ffdb000 Win32Thread: 00000000 WAIT: (UserRequest) UserMode Non-Alertable
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;8a2fe310 NotificationEvent
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;8974b6f0 SynchronizationEvent
&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;THREAD 89d86da8&amp;nbsp;&amp;nbsp;Cid 1cd0.1ba0&amp;nbsp;&amp;nbsp;Teb: 7ffda000 Win32Thread: 00000000 WAIT: (DelayExecution) UserMode Alertable
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;89d86e98 NotificationTimer
&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;THREAD 8902e020&amp;nbsp;&amp;nbsp;Cid 1cd0.1f9c&amp;nbsp;&amp;nbsp;Teb: 7ffd9000 Win32Thread: 00000000 WAIT: (DelayExecution) UserMode Alertable
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;8902e110 NotificationTimer
&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;THREAD 87b86020&amp;nbsp;&amp;nbsp;Cid 1cd0.0210&amp;nbsp;&amp;nbsp;Teb: 7ffd8000 Win32Thread: 00000000 WAIT: (DelayExecution) UserMode Alertable
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;87b86110 NotificationTimer
&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;THREAD 8971b828&amp;nbsp;&amp;nbsp;Cid 1cd0.13e0&amp;nbsp;&amp;nbsp;Teb: 7ffd7000 Win32Thread: 00000000 WAIT: (DelayExecution) UserMode Alertable
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;8971b918&amp;nbsp;&amp;nbsp;NotificationTimer
&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;THREAD 87ba5020&amp;nbsp;&amp;nbsp;Cid 1cd0.17e0&amp;nbsp;&amp;nbsp;Teb: 7ffd6000 Win32Thread: 00000000 WAIT: (UserRequest) UserMode Alertable
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;89d48fc0&amp;nbsp;&amp;nbsp;Mutant - owning thread 89d86da8
&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;THREAD 88724da8&amp;nbsp;&amp;nbsp;Cid 1cd0.1204&amp;nbsp;&amp;nbsp;Teb: 7ffd5000 Win32Thread: 00000000 WAIT: (DelayExecution) UserMode Alertable
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;88724e98 NotificationTimer
&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;THREAD 8869e548&amp;nbsp;&amp;nbsp;Cid 1cd0.1ec0&amp;nbsp;&amp;nbsp;Teb: 7ffd4000 Win32Thread: 00000000 READY
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;THREAD 88e28020&amp;nbsp;&amp;nbsp;Cid 1cd0.1a48&amp;nbsp;&amp;nbsp;Teb: 7ffaf000 Win32Thread: 00000000 READY
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;THREAD 88ab5020&amp;nbsp;&amp;nbsp;Cid 1cd0.1558&amp;nbsp;&amp;nbsp;Teb: 7ffae000 Win32Thread: 00000000 WAIT: (DelayExecution) UserMode Alertable
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;88ab5110 NotificationTimer
&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;THREAD 88827360&amp;nbsp;&amp;nbsp;Cid 1cd0.1d88&amp;nbsp;&amp;nbsp;Teb: 7ffad000 Win32Thread: 00000000 WAIT: (UserRequest) UserMode Alertable
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;89d48fc0&amp;nbsp;&amp;nbsp;Mutant - owning thread 89d86da8&lt;/span&gt;&lt;/pre&gt;
	&lt;p&gt;Fantastic, isn't it? Everything we've been looking for with trial-and-error analysis
with WinDbg/CDB is contained in this single output.&lt;/p&gt;

&lt;p&gt;But let's just look at the three important threads for this list (the two
which have a Mutant in their list of kernel objects, and the thread which is
specified as the owner for this mutant):&lt;/p&gt;

	&lt;pre class="Code"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;THREAD 89d86da8&amp;nbsp;&amp;nbsp;Cid 1cd0.1ba0&amp;nbsp;&amp;nbsp;Teb: 7ffda000 Win32Thread: 00000000 WAIT: (DelayExecution) UserMode Alertable
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;89d86e98 NotificationTimer&amp;nbsp;&lt;/span&gt;&lt;/pre&gt;
	&lt;pre class="Code"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;THREAD 87ba5020&amp;nbsp;&amp;nbsp;Cid 1cd0.17e0&amp;nbsp;&amp;nbsp;Teb: 7ffd6000 Win32Thread: 00000000 WAIT: (UserRequest) UserMode Alertable
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;89d48fc0&amp;nbsp;&amp;nbsp;Mutant - owning thread 89d86da8&amp;nbsp;&lt;/span&gt;&lt;/pre&gt;
	&lt;pre class="Code"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;THREAD 88827360&amp;nbsp;&amp;nbsp;Cid 1cd0.1d88&amp;nbsp;&amp;nbsp;Teb: 7ffad000 Win32Thread: 00000000 WAIT: (UserRequest) UserMode Alertable
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;89d48fc0&amp;nbsp;&amp;nbsp;Mutant - owning thread 89d86da8&lt;/span&gt;&lt;/pre&gt;
	&lt;p&gt;WAIT: (DelayExecution) in the first line means that the thread is
sleeping. The next line indicates the kernel object which the thread is waiting for. It
is a NotificationTimer and its a safe bet to assume that this is the timer
which has caused the DelayExecution in the first place. By the way:  If you've
forgotten to switch your user mode debugger into run mode - just like it
happens to me all the time  - your threads will be marked as &lt;i&gt;WAIT:
(Suspended) KernelMode Non-Alertable&lt;/i&gt;. In this case, just hit F5 or g in
your user mode debugger and re-try the !process command.&lt;/p&gt;

&lt;p&gt;The second and third thread in this list are both in WAIT: (UserRequest). The
synchronization object is in both cases the Mutant which is currently owned by
thread 89d86da8. This owner thread is the first thread in our list. To match
this information back to our user-mode information, we need to look at the
thread's Cid, which is 1cd0.1ba0 in our case. Of this Cid, the first part
(1cd0) is the Process ID and the second part (1ba0) is the Thread ID.&lt;/p&gt;

&lt;p&gt;If you then switch back to the user mode debugger and break into the application
(CTRL+BREAK), you can find the corresponding CLR thread by using !threads:&lt;/p&gt;

	&lt;pre class="Code"&gt;&lt;span&gt;0:013&amp;gt; &lt;/span&gt;&lt;span&gt;!threads&lt;/span&gt;&lt;span&gt;     // list all CLR threads
&lt;/span&gt;&lt;span&gt;ThreadCount: 12
UnstartedThread: 0
BackgroundThread: 1
PendingThread: 0
DeadThread: 0
Hosted Runtime: no
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;PreEmptive   GC Alloc           Lock
       ID OSID ThreadOBJ   State     GC       Context       Domain   Count APT Exception
   0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;1&amp;nbsp;&amp;nbsp;b70 00180fd0   200a020 Enabled&amp;nbsp;&amp;nbsp;00000000:00000000 0014c100     0 MTA
   2&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;2 1b54 00152480      b220 Enabled&amp;nbsp;&amp;nbsp;00000000:00000000 0014c100     0 MTA (Finalizer)
&lt;/span&gt;   3&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;3 1ba0 0019a1c0   200b020 Enabled&amp;nbsp;&amp;nbsp;00000000:00000000 0014c100     0 MTA
&lt;span&gt;   4&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;4 1f9c 0019c138   200b020 Enabled&amp;nbsp;&amp;nbsp;00000000:00000000 0014c100     0 MTA
   5&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;5&amp;nbsp;&amp;nbsp;210 0019cd18   200b020 Enabled&amp;nbsp;&amp;nbsp;00000000:00000000 0014c100     0 MTA
   6&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;6 13e0 0019d8d0   200b020 Enabled&amp;nbsp;&amp;nbsp;00000000:00000000 0014c100     0 MTA
   &lt;/span&gt;&lt;span&gt;7&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;7 17e0 0019e488   200b020 Enabled  00000000:00000000 0014c100     0 MTA
   &lt;/span&gt;&lt;span&gt;8&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;8 1204 0019f040   200b020 Enabled  00000000:00000000 0014c100     0 MTA
   9&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;9 1ec0 0019fbf8     b020  Disabled 00000000:00000000 0014c100     0 MTA
&amp;nbsp;&amp;nbsp;10&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;a 1a48 001a07b0     b020  Disabled 00000000:00000000 0014c100     0 MTA
&amp;nbsp;&amp;nbsp;11&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;b 1558 001a1368   200b020 Enabled&amp;nbsp;&amp;nbsp;00000000:00000000 0014c100     0 MTA
&amp;nbsp;&amp;nbsp;12&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;c 1d88 001a1f20   200b020 Enabled&amp;nbsp;&amp;nbsp;00000000:00000000 0014c100     0 MTA&lt;/span&gt;&lt;/pre&gt;
	&lt;p&gt;The third column in the thread list is called OSID and contains the
operating system thread id. If you look for the thread ID 1ba0 which we
retrieved from the kernel debugger's Cid, you will find that thread #3 is the
one who blocks the Mutex. This is the same information which we got from the first approach,
but now its a 100% deterministic and a lot simpler as well. I just needed to
let go of my fear of kernel debugging before venturing in this direction ...&lt;/p&gt;

&lt;/div&gt;&lt;img src="http://blogs.thinktecture.com/aggbug.aspx?PostID=414674" width="1" height="1"&gt;</description></item><item><title>Am I back? Let's see ...</title><link>http://blogs.thinktecture.com/ingo/archive/2006/08/05/414672.aspx</link><pubDate>Sat, 05 Aug 2006 09:06:00 GMT</pubDate><guid isPermaLink="false">ff4ed322-7612-4f43-9d7f-220c081c7cfd:414672</guid><dc:creator>Ingo</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.thinktecture.com/ingo/comments/414672.aspx</comments><wfw:commentRss>http://blogs.thinktecture.com/ingo/commentrss.aspx?PostID=414672</wfw:commentRss><description>&lt;p&gt;
  Yes, it's been a long while since my last post in Nov 2005. The short story of what has happend since about middle of last year:
  Rebecca is now 8 months and a bit and she's doing great, I've spent 43 weeks continously on the road (minus 2
  weeks when Rebecca was born and minus 1 week when we moved to another country) and I took a break of about eight
  weeks afterwards, mainly enjoying time with Becky and Katja, and started to learn gliding as we're living near a
  small airfield. Oh, yes, and I'm now living in Germany, near Landshut.
&lt;/p&gt;
&lt;p&gt;
  During the 43 weeks, I was able to work with a number of fantastic people and great teams. I spent even more time
  than before with the optimization of large-scale transaction processing systems and for the last few weeks, I've
  been spending way too much time with WinDbg, CDB and KD. So much time, in fact, that I started to prefer to console
  versions over WinDbg.
  &lt;br /&gt;
&lt;/p&gt;&lt;img src="http://blogs.thinktecture.com/aggbug.aspx?PostID=414672" width="1" height="1"&gt;</description></item><item><title>Rebecca Rammer, born November 12, 2005</title><link>http://blogs.thinktecture.com/ingo/archive/2005/11/14/414313.aspx</link><pubDate>Mon, 14 Nov 2005 02:31:00 GMT</pubDate><guid isPermaLink="false">ff4ed322-7612-4f43-9d7f-220c081c7cfd:414313</guid><dc:creator>Ingo</dc:creator><slash:comments>11</slash:comments><comments>http://blogs.thinktecture.com/ingo/comments/414313.aspx</comments><wfw:commentRss>http://blogs.thinktecture.com/ingo/commentrss.aspx?PostID=414313</wfw:commentRss><description>&lt;p&gt;
On Saturday, November 12, 2005 at 10:17pm, Rebecca Rammer was born.
&lt;/p&gt;
&lt;p&gt;
The technical data is well within the specs (3040 grams, 48 cm, 10 days
early), and baby and wife (and father) are doing great! :-)
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;img src="http://www.thinktecture.com/staff/ingo/weblog/blogimg/becky_01.jpg" height="427" width="640"&gt;
&lt;br&gt;&lt;br&gt;
&lt;img src="http://www.thinktecture.com/staff/ingo/weblog/blogimg/becky_02.jpg" height="427" width="640"&gt;
&lt;img src="http://blogs.thinktecture.com/aggbug.aspx?PostID=414313" width="1" height="1"&gt;</description></item><item><title>Latency vs. Bandwidth – Developers vs. Einstein</title><link>http://blogs.thinktecture.com/ingo/archive/2005/11/08/LatencyVsBandwidth.aspx</link><pubDate>Tue, 08 Nov 2005 19:38:00 GMT</pubDate><guid isPermaLink="false">ff4ed322-7612-4f43-9d7f-220c081c7cfd:414304</guid><dc:creator>Ingo</dc:creator><slash:comments>5</slash:comments><comments>http://blogs.thinktecture.com/ingo/comments/414304.aspx</comments><wfw:commentRss>http://blogs.thinktecture.com/ingo/commentrss.aspx?PostID=414304</wfw:commentRss><description>One piece of &lt;I&gt;The Ultimate Wisdom&lt;/I&gt; which is quoted quite often is that "chatty interfaces kill the performance of a distributed application". But actually, it's not the chatty interface which kills it - the &lt;I&gt;really&lt;/I&gt; limiting factor is instead one of the handful of unchallenged physical constants of this universe: the speed of light. But let me come back to this later. 
&lt;P&gt;Whenever &lt;I&gt;something&lt;/I&gt; - and this can be something non-physical like a stream of bytes or a huge chunk of extremely physical rocks - needs to move, you can choose between a set of different alternatives in the way you transport it: You can transfer as much as possible in one go, or alternatively, you could take multiple round trips with smaller amounts of your payload. When you're a teenager moving out of your parent's house, you will quite likely just pack your stuff into your and your friend's cars and just hit the road, going back and forth a few times just to get out as quickly as possible. Years later, after you bought and sold the right stock at the right time, you might instead hire someone to move everything from your 8 bedroom home in one state to your new mansion in a different state using just one big truck and trailer. (Unless of course, you had &lt;I&gt;special help&lt;/I&gt; with your choice of stocks, in which case &lt;I&gt;somebody&lt;/I&gt; will move &lt;I&gt;you&lt;/I&gt; with a rather small car to a rather small room in your final roundtrip for the next 15 years.) &lt;/P&gt;
&lt;P&gt;&lt;B&gt;Is Bigger Better?&lt;/B&gt;&lt;/P&gt;
&lt;P&gt;Despite the fact that reducing the number of roundtrips usually decreases the complete processing time, the usage of smaller units of transportation also has a few advantages: you can for example unpack the first boxes and start using their contents while the rest of your flat is still being sent in smaller packages. That’s what we ended up calling streaming. (My wife would now point out the fact that &lt;I&gt;somebody&lt;/I&gt; in our family always managed to be out of the country whenever the two of us moved. That’s what we ended up calling &lt;I&gt;slipping away&lt;/I&gt;. Unless you are my wife, in which case you would have use a slightly more explicit term.) &lt;/P&gt;
&lt;P&gt;You also get the benefit of being able to use the smaller self-contained packages which might arrive out of sequence. In computer systems, this is sometimes implemented by only returning a small response (let’s say only the header information) as the answer of a synchronous request while returning the detailed information asynchronously using a message queuing system. In real life, I tend to implement this during my regular commuter flights: no matter whether or not my checked bags are delayed or re-routed, I will always have my computer, a power adapter, a toothbrush, and clothes for the next day in my carry on luggage. Especially when traveling via CDG or LHR. &lt;/P&gt;
&lt;P&gt;&lt;/P&gt;
&lt;P&gt;&lt;B&gt;The Speed Of Light – Or: In Doubt, Assume Bandwidth&lt;/B&gt;&lt;/P&gt;
&lt;P&gt;But in any case: the general recommendation is that chunky interfaces are better than chatty ones. This suggestion is based on the belief that, in doubt, you should assume high bandwidth but not low latency. And this belief in turn is grounded in one ultimate fact: the former can be bought with money – the latter can’t. &lt;/P&gt;
&lt;P&gt;I’ve been online since 94. At that time I used a 1200 baud modem to connect to the Internet via terminal dial-in to a Unix box. For me the WWW was Lynx, but that’s a completely different story. At that time, I could send a &lt;I&gt;ping&lt;/I&gt; from Europe to the US in about 1200 milliseconds. Today, I can roundtrip the same ping in about 120 milliseconds. But today, I can download the full 3629.6 MB of Visual Studio 2005 Team Suite in approximately 6 hours from a random hotel room. This is coincidentally what I’m doing right now which triggered the writing of this article. &lt;/P&gt;
&lt;P&gt;&lt;B&gt;The Long Walk&lt;/B&gt;&lt;/P&gt;
&lt;P&gt;If I would have done the same thing back in ’94, it would have taken roughly 367 days to transfer the 3,805,911,450 bytes with approximately 120 bytes per second, including start/stop bits and hardware compression. Just to put this into perspective: let’s assume that your hotel room is at the point on this earth which is the farthest away from Redmond. (The fact that penguins will be the only neighbors on this small island might make you think again about the likely roots of the Linux mascot.) If you would have received divine help to walk over water towards the Microsoft HQ, something interesting would have happened: With a swift pace of 5 kilometers (3.1 miles) per hour for 12 hours a day, you would have finished the roughly 20,000 kilometers (12,427 miles) on the earth’s surface in 333 days (23.7 fortnights) which means that you would have had your hands on Visual Studio about a month earlier than your friend who started the download at the same time when you left the island. &lt;/P&gt;
&lt;P&gt;Now, of course, this would not have helped you too much as you would have had to wait two more years for a DVD player to become available 1997. &lt;/P&gt;
&lt;P&gt;But I think that it’s really interesting to see that the end-to-end bandwidth increased by 1468 times within the last 11 years while the latency (the time a single &lt;I&gt;ping&lt;/I&gt; takes) has only been improved tenfold. If this wouldn’t be enough, there is even a natural cap on latency. The minimum round-trip time between two points of this earth is determined by the maximum speed of information transmission: the speed of light. At roughly 300,000 kilometers per second (3.6 * 10E12 teraangstrom per fortnight), it will &lt;I&gt;always&lt;/I&gt; take at least 30 milliseconds to send a ping from Europe to the US and back, even if the processing would be done in real time. &lt;/P&gt;
&lt;P&gt;That’s why most people recommend chunky interfaces instead of chatty ones to optimize for higher latency instead of smaller bandwidths: The latter will be solved automatically; the former only if you prove Einstein wrong. &lt;/P&gt;&lt;/B&gt;&lt;/B&gt;&lt;img src="http://blogs.thinktecture.com/aggbug.aspx?PostID=414304" width="1" height="1"&gt;</description></item></channel></rss>