From 1b211df0d603ea627f924b4440573512c229902b Mon Sep 17 00:00:00 2001 From: Atsushi Eno Date: Tue, 6 Oct 2009 09:32:38 +0000 Subject: [PATCH] 2009-10-06 Atsushi Enomoto * SvcHttpHandler.cs, HttpChannelListener.cs : some significant rewrite to handle shutdown situation better. The listeners should not close channels that it opened. Instead, just stop accepting further requests. Removed blocking mutex on WaitForRequest(). Now xsp shuts down as expected. svn path=/trunk/mcs/; revision=143498 --- .../System.ServiceModel.Channels/ChangeLog | 8 +++ .../HttpChannelListener.cs | 18 +++-- .../SvcHttpHandler.cs | 66 +++++++++++-------- 3 files changed, 56 insertions(+), 36 deletions(-) diff --git a/mcs/class/System.ServiceModel/System.ServiceModel.Channels/ChangeLog b/mcs/class/System.ServiceModel/System.ServiceModel.Channels/ChangeLog index b60acb6ccb8..8b9d540fc9c 100755 --- a/mcs/class/System.ServiceModel/System.ServiceModel.Channels/ChangeLog +++ b/mcs/class/System.ServiceModel/System.ServiceModel.Channels/ChangeLog @@ -1,3 +1,11 @@ +2009-10-06 Atsushi Enomoto + + * SvcHttpHandler.cs, HttpChannelListener.cs : some significant + rewrite to handle shutdown situation better. The listeners should + not close channels that it opened. Instead, just stop accepting + further requests. Removed blocking mutex on WaitForRequest(). + Now xsp shuts down as expected. + 2009-10-06 Atsushi Enomoto * HttpReplyChannel.cs : lock list when releasing its content contexts. diff --git a/mcs/class/System.ServiceModel/System.ServiceModel.Channels/HttpChannelListener.cs b/mcs/class/System.ServiceModel/System.ServiceModel.Channels/HttpChannelListener.cs index a3b88a2e587..0bb1223be40 100644 --- a/mcs/class/System.ServiceModel/System.ServiceModel.Channels/HttpChannelListener.cs +++ b/mcs/class/System.ServiceModel/System.ServiceModel.Channels/HttpChannelListener.cs @@ -130,6 +130,17 @@ namespace System.ServiceModel.Channels throw new NotSupportedException (String.Format ("Channel type {0} is not supported", typeof (TChannel))); } + + protected override void OnAbort () + { + HttpHandler.CloseServiceChannel (); + } + + protected override void OnClose (TimeSpan timeout) + { + HttpHandler.CloseServiceChannel (); + base.OnClose (timeout); + } } internal abstract class HttpChannelListenerBase : InternalChannelListenerBase @@ -159,14 +170,9 @@ namespace System.ServiceModel.Channels get { return encoder; } } - protected IList Channels { - get { return channels; } - } - protected override TChannel OnAcceptChannel (TimeSpan timeout) { TChannel ch = CreateChannel (timeout); - Channels.Add (ch); return ch; } @@ -189,8 +195,6 @@ namespace System.ServiceModel.Channels protected override void OnClose (TimeSpan timeout) { DateTime start = DateTime.Now; - foreach (TChannel ch in new List (Channels)) // they will be removed during iteration, so create another one - ch.Close (timeout - (DateTime.Now - start)); base.OnClose (timeout - (DateTime.Now - start)); } } diff --git a/mcs/class/System.ServiceModel/System.ServiceModel.Channels/SvcHttpHandler.cs b/mcs/class/System.ServiceModel/System.ServiceModel.Channels/SvcHttpHandler.cs index d9f8ecde6dc..b2e19b800ce 100644 --- a/mcs/class/System.ServiceModel/System.ServiceModel.Channels/SvcHttpHandler.cs +++ b/mcs/class/System.ServiceModel/System.ServiceModel.Channels/SvcHttpHandler.cs @@ -47,9 +47,9 @@ namespace System.ServiceModel.Channels { Uri request_url; ServiceHostBase host; Queue pending = new Queue (); - bool closing; + int close_state; - AutoResetEvent wait = new AutoResetEvent (false); + AutoResetEvent process_request_wait = new AutoResetEvent (false); AutoResetEvent listening = new AutoResetEvent (false); public SvcHttpHandler (Type type, Type factoryType, string path) @@ -70,18 +70,25 @@ namespace System.ServiceModel.Channels { public HttpContext WaitForRequest (TimeSpan timeout) { + if (close_state > 0) + return null; DateTime start = DateTime.Now; + + if (close_state > 0) + return null; + if (pending.Count == 0) { + if (!process_request_wait.WaitOne (timeout - (DateTime.Now - start), false) || close_state > 0) + return null; + } + HttpContext ctx; lock (pending) { - if (pending.Count > 0) { - var ctx = pending.Dequeue (); - if (ctx.AllErrors != null && ctx.AllErrors.Length > 0) - return WaitForRequest (timeout - (DateTime.Now - start)); - return ctx; - } + if (pending.Count == 0) + return null; + ctx = pending.Dequeue (); } - - return wait.WaitOne (timeout - (DateTime.Now - start), false) && !closing ? - WaitForRequest (timeout - (DateTime.Now - start)) : null; + if (ctx.AllErrors != null && ctx.AllErrors.Length > 0) + return WaitForRequest (timeout - (DateTime.Now - start)); + return ctx; } public void ProcessRequest (HttpContext context) @@ -89,10 +96,10 @@ namespace System.ServiceModel.Channels { request_url = context.Request.Url; EnsureServiceHost (); pending.Enqueue (context); + process_request_wait.Set (); - wait.Set (); - - listening.WaitOne (); + if (close_state == 0) + listening.WaitOne (); } public void EndRequest (HttpContext context) @@ -100,14 +107,26 @@ namespace System.ServiceModel.Channels { listening.Set (); } + // called from SvcHttpHandlerFactory's remove callback (i.e. + // unloading asp.net). It closes ServiceHost, then the host + // in turn closes the listener and the channels it opened. + // The channel listener calls CloseServiceChannel() to stop + // accepting further requests on its shutdown. public void Close () { - closing = true; - listening.Set (); - wait.Set (); host.Close (); host = null; - closing = false; + } + + // called from AspNetChannelListener.Close() or .Abort(). + public void CloseServiceChannel () + { + if (close_state > 0) + return; + close_state = 1; + process_request_wait.Set (); + listening.Set (); + close_state = 2; } void EnsureServiceHost () @@ -124,18 +143,7 @@ namespace System.ServiceModel.Channels { host = new ServiceHost (type, baseUri); host.Extensions.Add (new VirtualPathExtension (baseUri.AbsolutePath)); - /* - if (host.Description.Endpoints.Count == 0) - //FIXME: Binding: Get from web.config. - host.AddServiceEndpoint (ContractDescription.GetContract (type).Name, - new BasicHttpBinding (), new Uri (path, UriKind.Relative)); - - var c = host.BaseAddresses; - */ - host.Open (); - - //listening.WaitOne (); } } } -- 2.25.1