[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;
+ }
+ }
+}