[Mono-bugs] [Bug 52982][Cri] New - CrossAppDomain is blocking at AppDomain.DoCallBack

bugzilla-daemon@bugzilla.ximian.com bugzilla-daemon@bugzilla.ximian.com
Fri, 16 Jan 2004 20:19:38 -0500 (EST)


Please do not reply to this email- if you want to comment on the bug, go to the
URL shown below and enter your comments there.

Changed by derek.mcumber@datamtnsol.com.

http://bugzilla.ximian.com/show_bug.cgi?id=52982

--- shadow/52982	2004-01-16 20:19:37.000000000 -0500
+++ shadow/52982.tmp.16765	2004-01-16 20:19:38.000000000 -0500
@@ -0,0 +1,338 @@
+Bug#: 52982
+Product: Mono/Runtime
+Version: unspecified
+OS: 
+OS Details: 
+Status: NEW   
+Resolution: 
+Severity: Unknown
+Priority: Critical
+Component: misc
+AssignedTo: mono-bugs@ximian.com                            
+ReportedBy: derek.mcumber@datamtnsol.com               
+QAContact: mono-bugs@ximian.com
+TargetMilestone: ---
+URL: 
+Cc: 
+Summary: CrossAppDomain is blocking at AppDomain.DoCallBack
+
+In running XSP on Windows there is a blocking issue that causes a memory
+leak of roughly 5Meg per page request.  the test case below will stream
+the Home_Mono.htm (if you SaveAs... from the go-mono.com site) from the
+current directory 25 times and use 90Meg on a Windows machine.
+
+Steps to reproduce the problem:
+1. Compile Class1.cs
+2. Set Mono_Path and Mono_Cfg_Dir
+3. execuce compiled .exe
+
+Actual Results:
+All threads started in ThreadPool.c block at AppDomain.DoCallBack
+and the .exe and .dlls appear to continue to reload.
+
+Running Xsp.exe on a Mono release 0.28 or later and viewing pages
+while watching TaskManager will show similar results.
+
+Expected Results:
+Load once and use minimimal memory
+
+How often does this happen? 
+Every Time
+
+Additional Information:
+Sorry about the sloppy test case...
+
+using System;
+using System.Configuration;
+using System.Diagnostics;
+using System.IO;
+using System.Net;
+using System.Net.Sockets;
+using System.Reflection;
+using System.Threading;
+using System.Web.Hosting;
+using System.Text;
+using System.Collections;
+using System.Web;
+
+namespace Mono.ASPNET
+{
+        public interface IApplicationHost
+        {
+                string Path { get; }        
+                string VPath { get; }        
+                AppDomain Domain { get; }        
+        }
+
+        public class XSPApplicationHost : MarshalByRefObject, IApplicationHost
+        {
+                string path;
+                string vpath;
+
+                public override object InitializeLifetimeService ()
+                {
+                        return null; // who wants to live forever?
+                }
+                
+                public string Path {
+                        get {
+                                if (path == null)
+                                        path =
+AppDomain.CurrentDomain.GetData (".appPath").ToString ();
+
+                                return path;
+                        }
+                }
+
+                public string VPath {
+                        get {
+                                if (vpath == null)
+                                        vpath = 
+AppDomain.CurrentDomain.GetData (".appVPath").ToString ();
+
+                                return vpath;
+                        }
+                }
+
+                public AppDomain Domain {
+                        get { return AppDomain.CurrentDomain; }
+                }
+        }
+
+        [Serializable]
+        public class RequestData
+        {
+                public string Verb;
+                public string Path;
+                public string PathInfo;
+                public string QueryString;
+                public string Protocol;
+                public byte [] InputBuffer;
+
+                public RequestData (string verb, string path, string
+queryString, string protocol)
+                {
+                        this.Verb = verb;
+                        this.Path = path;
+                        this.QueryString = queryString;
+                        this.Protocol = protocol;
+                }
+
+                public override string ToString ()
+                {
+                        StringBuilder sb = new StringBuilder ();
+                        sb.AppendFormat ("Verb: {0}\n", Verb);
+                        sb.AppendFormat ("Path: {0}\n", Path);
+                        sb.AppendFormat ("PathInfo: {0}\n", PathInfo);
+                        sb.AppendFormat ("QueryString: {0}\n", QueryString);
+                        return sb.ToString ();
+                }
+        }
+
+
+        [Serializable]
+        class Worker
+        {
+                [NonSerialized] XSPApplicationServer server;
+                IApplicationHost host;
+                NetworkStream ns;
+                bool requestFinished;
+                RequestData rdata;
+                EndPoint remoteEP;
+                EndPoint localEP;
+
+                public Worker (XSPApplicationServer server)
+                {
+                        this.server = server;
+                }
+
+                public void Run (object state)
+                {
+                        try {
+                                rdata = new RequestData("GET",
+"/Home_Mono.htm", string.Empty, "HTTP/1.0");
+					  //if (host == null) {
+						//object o = ApplicationHost.CreateApplicationHost (typeof
+(XSPApplicationHost),
+                                      //                               
+virtualPath,
+                                      //                               
+baseDirectory);
+					  //}
+                                host = server.GetApplicationForPath
+("/Home_Mono.htm", true);
+
+					  Console.WriteLine("Heap Space Before CrossAppDD: "+
+GC.GetTotalMemory(false).ToString());
+					  
+                                CrossAppDomainDelegate pr = new
+CrossAppDomainDelegate (ProcessRequest);
+					  if (host == null) {
+						Console.WriteLine("Host is null");
+					  }
+					  if (pr == null) {
+						Console.WriteLine("PR is null");
+					  }
+                                host.Domain.DoCallBack (pr);
+                        } catch (Exception e) {
+					  Console.WriteLine("Exception: "+e.Message);
+                        } finally {
+					  Console.WriteLine("Heap Space after finally: "+
+GC.GetTotalMemory(false).ToString());
+                                requestFinished = true;
+                                try {
+                                        ns.Close ();
+                                } catch {}
+                        }
+                }
+
+                public void ProcessRequest ()
+                {
+ 				StringWriter writer = new StringWriter();
+				Console.WriteLine("Streaming "+rdata.Path);
+				SimpleWorkerRequest hwr = 
+      				new SimpleWorkerRequest(rdata.Path, string.Empty, writer);
+				writer.Flush();
+				Console.WriteLine("Calling HttpRuntime.ProcessRequest");
+    				HttpRuntime.ProcessRequest(hwr);
+				Console.WriteLine("Finished HttpRuntime.ProcessRequest");
+				Console.WriteLine(writer.GetStringBuilder().ToString());
+                }
+        }
+
+        public class XSPApplicationServer
+        {
+                Socket listen_socket;
+                bool started;
+                bool stop;
+                Thread runner;
+                Hashtable appToDir;
+                Hashtable dirToHost;
+                object marker = new object ();
+
+                public XSPApplicationServer (string applications)
+                {
+                        SetApplications (applications);
+                }
+
+                public void SetApplications (string applications)
+                {
+                        if (applications == null)
+                                throw new ArgumentNullException
+("applications");
+ 
+                        if (appToDir != null)
+                                throw new InvalidOperationException
+("Already called");
+ 
+                        if (applications == "")
+                                return;
+
+                        appToDir = new Hashtable ();
+                        dirToHost = new Hashtable ();
+                        string [] apps = applications.Split (',');
+                        Console.WriteLine ("applications: {0}", applications);
+                        foreach (string str in apps) {
+                                string [] app = str.Split (':');
+                                if (app.Length != 2)
+                                        throw new ArgumentException
+("Should be something like VPath:realpath");
+ 
+                                string fp = System.IO.Path.GetFullPath (app
+[1]);
+                                Console.WriteLine ("{0} -> {1}", app [0], fp);
+                                appToDir [app [0]] = fp;
+                                dirToHost [fp] = marker;
+                        }
+                }
+ 
+                public void Start ()
+                {
+                        if (started)
+                                throw new InvalidOperationException ("The
+server is already started.");
+
+                        if (appToDir == null)
+                                throw new InvalidOperationException
+("SetApplications must be called first");
+
+                        runner = new Thread (new ThreadStart (RunServer));
+                        runner.IsBackground = true;
+                        runner.Start ();
+                        stop = false;
+                }
+
+                public void Stop ()
+                {
+                        if (!started)
+                                throw new InvalidOperationException ("The
+server is not started.");
+
+                        stop = true;        
+                        listen_socket.Close ();
+                        dirToHost = new Hashtable ();
+                }
+
+                private void RunServer ()
+                {
+                        started = true;
+				int i=0;
+                        while (i < 25){
+					  Console.WriteLine("Creating Worker and adding to thread pool");
+                                Worker worker = new Worker (this);
+                                ThreadPool.QueueUserWorkItem (new
+WaitCallback (worker.Run));
+					  i++;
+                        }
+
+                        started = false;
+                }
+
+                public static object CreateApplicationHost (string
+virtualPath, string baseDirectory)
+                {
+				Console.WriteLine("Createing apphost {0} and {0}", virtualPath,
+baseDirectory);
+                        return ApplicationHost.CreateApplicationHost
+(typeof (XSPApplicationHost),
+                                                                     
+virtualPath,
+                                                                     
+baseDirectory);
+                }
+
+                public IApplicationHost GetApplicationForPath (string path,
+bool defaultToRoot)
+                {
+                        IApplicationHost bestFit = null;
+				string dir = appToDir ["/"] as string;
+                        object o = dirToHost [dir];
+				if (o == marker) {
+                            o = CreateApplicationHost ("/", dir);
+                            dirToHost [dir] = o;
+                        }
+				bestFit = dirToHost [appToDir ["/"]] as IApplicationHost;
+                        return bestFit;
+                }
+        }
+
+	public class TestServer
+	{
+                
+		public static int Main (string [] args)
+		{
+			string apps = "/:.";
+			object oport = 8080;
+			string ip = "0.0.0.0";
+
+			string rootDir = Directory.GetCurrentDirectory ();
+                        
+			XSPApplicationServer server =  new XSPApplicationServer (apps);
+
+			server.Start ();
+			Console.WriteLine ("Hit Return to stop the server.");
+			Console.ReadLine ();
+			return 0;
+		}
+	}
+}