2009-10-06 Atsushi Enomoto <atsushi@ximian.com>
authorAtsushi Eno <atsushieno@gmail.com>
Tue, 6 Oct 2009 09:32:38 +0000 (09:32 -0000)
committerAtsushi Eno <atsushieno@gmail.com>
Tue, 6 Oct 2009 09:32:38 +0000 (09:32 -0000)
* 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

mcs/class/System.ServiceModel/System.ServiceModel.Channels/ChangeLog
mcs/class/System.ServiceModel/System.ServiceModel.Channels/HttpChannelListener.cs
mcs/class/System.ServiceModel/System.ServiceModel.Channels/SvcHttpHandler.cs

index b60acb6ccb8417c81704edfd73cd0d5a3c55cd32..8b9d540fc9cdf49fedc6616ad9c0ebbb4c1329b3 100755 (executable)
@@ -1,3 +1,11 @@
+2009-10-06  Atsushi Enomoto  <atsushi@ximian.com>
+
+       * 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  <atsushi@ximian.com>
 
        * HttpReplyChannel.cs : lock list when releasing its content contexts.
index a3b88a2e58729a52afd9bf84f5a605b0dd1a3162..0bb1223be40b1543fa442fad6ae91fb72a96748e 100644 (file)
@@ -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<TChannel> : InternalChannelListenerBase<TChannel>
@@ -159,14 +170,9 @@ namespace System.ServiceModel.Channels
                        get { return encoder; }
                }
 
-               protected IList<TChannel> 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<TChannel> (Channels)) // they will be removed during iteration, so create another one
-                               ch.Close (timeout - (DateTime.Now - start));
                        base.OnClose (timeout - (DateTime.Now - start));
                }
        }
index d9f8ecde6dca1170df0759dbcaff8cdced87c741..b2e19b800cea59794bf7175237935740a82a0325 100644 (file)
@@ -47,9 +47,9 @@ namespace System.ServiceModel.Channels {
                Uri request_url;
                ServiceHostBase host;
                Queue<HttpContext> pending = new Queue<HttpContext> ();
-               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 ();
                }
        }
 }