2008-12-05 Marek Habersack <mhabersack@novell.com>
authorMarek Habersack <grendel@twistedcode.net>
Fri, 5 Dec 2008 18:12:51 +0000 (18:12 -0000)
committerMarek Habersack <grendel@twistedcode.net>
Fri, 5 Dec 2008 18:12:51 +0000 (18:12 -0000)
* BuildManager.cs: attempt to enter the compilation critical
section with a timeout up to 3 times before giving up. This avoids
deadlocks in situations where there are two virtual directores
each containing user controls referencing user controls from the
other directory.

svn path=/trunk/mcs/; revision=120861

mcs/class/System.Web/System.Web.Compilation/BuildManager.cs
mcs/class/System.Web/System.Web.Compilation/ChangeLog

index 20c2636dc2c94d672364e02a3df4d030741ceb09..7f421caa54d5f7dad4ec6517c3761baeb26f4b06 100644 (file)
@@ -1008,7 +1008,9 @@ namespace System.Web.Compilation {
                        if (dothrow)
                                throw new HttpException (404, "The file '" + virtualPath + "' does not exist.");
                }
-               
+
+               const int ticketLockTimeout = 20000;
+               const int ticketLockAttempts = 3;
                static void BuildAssembly (VirtualPath virtualPath)
                {
                        AssertVirtualPathExists (virtualPath);
@@ -1016,6 +1018,7 @@ namespace System.Web.Compilation {
                        
                        object ticket;
                        bool acquired;
+                       bool locked = false;
                        string virtualDir = virtualPath.Directory;
                        BuildKind buildKind = BuildKind.Unknown;
                        bool kindPushed = false;
@@ -1023,7 +1026,16 @@ namespace System.Web.Compilation {
                        
                        acquired = AcquireCompilationTicket (virtualDir, out ticket);
                        try {
-                               Monitor.Enter (ticket);
+                               int attempts = ticketLockAttempts;
+                               while (attempts-- > 0) {
+                                       if (Monitor.TryEnter (ticket, ticketLockTimeout)) {
+                                               locked = true;
+                                               break;
+                                       }
+                               }
+                               if (!locked)
+                                       throw new HttpException (500, "Failed to acquire compilation lock for virtual path '" + virtualPath + "'.");
+                               
                                lock (buildCacheLock) {
                                        if (buildCache.ContainsKey (vpAbsolute))
                                                return;
@@ -1118,10 +1130,12 @@ namespace System.Web.Compilation {
                                                recursiveBuilds.Pop ();
                                        }
                                }
-                               
-                               Monitor.Exit (ticket);
-                               if (acquired)
-                                       ReleaseCompilationTicket (virtualDir);
+
+                               if (locked) {
+                                       Monitor.Exit (ticket);
+                                       if (acquired)
+                                               ReleaseCompilationTicket (virtualDir);
+                               }
                        }
                }
 
index 0babcbce009dbac2752a0177b6cef74d76e52766..46af22852df53ccf91bf8ddac84e8bf62b812d3e 100644 (file)
@@ -1,3 +1,10 @@
+2008-12-05  Marek Habersack  <mhabersack@novell.com>
+
+       * BuildManager.cs: attempt to enter the compilation critical
+       section with a timeout up to 3 times before giving up. This avoids
+       deadlocks in situations where there are two virtual directores
+       each containing user controls referencing user controls from the
+       other directory.
 
 2008-12-02 Gonzalo Paniagua Javier <gonzalo@novell.com>