Merge pull request #463 from strawd/concurrent-requests
authorMiguel de Icaza <miguel@gnome.org>
Wed, 23 Sep 2015 18:37:01 +0000 (14:37 -0400)
committerMiguel de Icaza <miguel@gnome.org>
Wed, 23 Sep 2015 18:37:01 +0000 (14:37 -0400)
Handle multiple concurrent calls to BeginTryReceiveRequest

1  2 
mcs/class/System.ServiceModel/System.ServiceModel.Channels.Http/HttpReplyChannel.cs
mcs/class/System.ServiceModel/System.ServiceModel.Channels/ReplyChannelBase.cs

index 16c38c77932c39409c4349ee2ea501d67051c820,378a200ff216c304ec3c1ad0a95a6efbe38112b2..03e7cad1f1c4f7eff0afaab6e7c41ebd1801f848
@@@ -92,8 -92,8 +92,8 @@@ namespace System.ServiceModel.Channels.
                        AbortConnections (timeout);
                        // FIXME: this wait is sort of hack (because it should not be required), but without it some tests are blocked.
                        // This hack even had better be moved to base.CancelAsync().
                      if (CurrentAsyncResult != null)
                              CurrentAsyncResult.AsyncWaitHandle.WaitOne (TimeSpan.FromMilliseconds (300));
//                    if (CurrentAsyncResult != null)
//                            CurrentAsyncResult.AsyncWaitHandle.WaitOne (TimeSpan.FromMilliseconds (300));
                        return base.CancelAsync (timeout);
                }
  
  
                        Message msg = null;
  
 -                      if (ctxi.Request.HttpMethod == "POST") {
 +                      if (ctxi.Request.HttpMethod == "POST")
                                msg = CreatePostMessage (ctxi);
 -                              if (msg == null)
 -                                      return false;
 -                      } else if (ctxi.Request.HttpMethod == "GET")
 +                      else if (ctxi.Request.HttpMethod == "GET")
                                msg = Message.CreateMessage (MessageVersion.None, null); // HTTP GET-based request
  
 +                      if (msg == null)
 +                              return false;
 +
                        if (msg.Headers.To == null)
                                msg.Headers.To = ctxi.Request.Url;
                        msg.Properties.Add ("Via", LocalAddress.Uri);
index d73b0866495cf0a32fe3ef8b2796ea619e8a36f2,9a66a32450063f6085f71f90d25a90a5f3b7e081..4e47ecf0035d8fda5470806c3f5ad8686b0c21f7
@@@ -29,13 -29,11 +29,13 @@@ using System
  using System.Collections.Generic;
  using System.IO;
  using System.Net;
 +using System.Net.Sockets;
  using System.Net.Security;
  using System.ServiceModel;
  using System.ServiceModel.Description;
  using System.ServiceModel.Security;
  using System.Threading;
 +using System.Xml;
  
  namespace System.ServiceModel.Channels
  {
  
                protected override void OnClose (TimeSpan timeout)
                {
-                       if (CurrentAsyncThread != null)
+                       if (currentAsyncThreads.Count > 0)
                                if (!CancelAsync (timeout))
-                                       CurrentAsyncThread.Abort ();
+                                       foreach (Thread asyncThread in currentAsyncThreads)
+                                               asyncThread.Abort ();
                }
  
                public virtual bool CancelAsync (TimeSpan timeout)
                {
                        // FIXME: It should wait for the actual completion.
-                       return CurrentAsyncResult == null;
+                       return currentAsyncResults.Count > 0;
                        //return CurrentAsyncResult == null || CurrentAsyncResult.AsyncWaitHandle.WaitOne (timeout);
                }
  
                TryReceiveDelegate try_recv_delegate;
  
                object async_result_lock = new object ();
-               protected Thread CurrentAsyncThread { get; private set; }
-               protected IAsyncResult CurrentAsyncResult { get; private set; }
+               HashSet<Thread> currentAsyncThreads = new HashSet<Thread>();
+               HashSet<IAsyncResult> currentAsyncResults = new HashSet<IAsyncResult>();
  
                public virtual IAsyncResult BeginTryReceiveRequest (TimeSpan timeout, AsyncCallback callback, object state)
                {
-                       if (CurrentAsyncResult != null)
-                               throw new InvalidOperationException ("Another async TryReceiveRequest operation is in progress");
+                       IAsyncResult result = null;
                        if (try_recv_delegate == null)
                                try_recv_delegate = new TryReceiveDelegate (delegate (TimeSpan tout, out RequestContext ctx) {
                                        lock (async_result_lock) {
-                                               if (CurrentAsyncResult != null)
-                                                       CurrentAsyncThread = Thread.CurrentThread;
+                                               if (currentAsyncResults.Contains (result))
+                                                       currentAsyncThreads.Add (Thread.CurrentThread);
                                        }
                                        try {
                                                return TryReceiveRequest (tout, out ctx);
 +                                      } catch (XmlException ex) {
 +                                              Console.WriteLine ("Xml Exception (Dropped Connection?):" + ex.Message);
 +                                              //on dropped connection, 
 +                                              //whatever you do don't crash
 +                                              //the whole app.  Ignore for now
 +                                      } catch (SocketException ex) {
 +                                              Console.WriteLine ("Socket Exception (Dropped Connection?):" + ex.Message);
 +                                              //on dropped connection, 
 +                                              //whatever you do don't crash
 +                                              //the whole app.  Ignore for now
 +                                      } catch (IOException ex) {
 +                                              Console.WriteLine ("I/O Exception (Dropped Connection?):" + ex.Message);
 +                                              //on dropped connection, 
 +                                              //whatever you do don't crash
 +                                              //the whole app.  Ignore for now
                                        } finally {
                                                lock (async_result_lock) {
-                                                       CurrentAsyncResult = null;
-                                                       CurrentAsyncThread = null;
+                                                       currentAsyncResults.Remove (result);
+                                                       currentAsyncThreads.Remove (Thread.CurrentThread);
                                                }
                                        }
 +                                      ctx = null;
 +                                      return false;
                                        });
                        RequestContext dummy;
-                       IAsyncResult result;
                        lock (async_result_lock) {
-                               result = CurrentAsyncResult = try_recv_delegate.BeginInvoke (timeout, out dummy, callback, state);
+                               result = try_recv_delegate.BeginInvoke (timeout, out dummy, callback, state);
+                               currentAsyncResults.Add (result);
                        }
-                       // Note that at this point CurrentAsyncResult can be null here if delegate has run to completion
+                       // Note that at this point result can be missing from currentAsyncResults here if delegate has run to completion
                        return result;
                }