[System.Xaml] Fix deadlock on exception in XamlBackgroundReader
authorAlexander Köplinger <alex.koeplinger@outlook.com>
Fri, 8 Sep 2017 14:36:06 +0000 (16:36 +0200)
committerMarek Safar <marek.safar@gmail.com>
Mon, 11 Sep 2017 09:31:42 +0000 (11:31 +0200)
The ManualResetEvent wouldn't be signaled when an exception happens
in the reader loop so we'd deadlock in Read().

I'm still investigating where the exception comes from but this
should at least help unblocking CI.

https://bugzilla.xamarin.com/show_bug.cgi?id=46683

mcs/class/System.Xaml/System.Xaml/XamlBackgroundReader.cs

index 2859a14a9d999c5d1f838cbd6c00c52b4ebbae5a..d1d54491fd87ca3c4f00e6111ac1b7e083702161 100644 (file)
@@ -23,6 +23,7 @@
 using System;
 using System.Collections.Generic;
 using System.Threading;
+using System.Runtime.ExceptionServices;
 
 namespace System.Xaml
 {
@@ -40,6 +41,7 @@ namespace System.Xaml
                XamlReader r;
                XamlNodeQueue q;
                bool read_all_done, do_work = true;
+               ExceptionDispatchInfo read_exception;
                ManualResetEvent wait = new ManualResetEvent (true);
 
                public bool HasLineInfo {
@@ -92,6 +94,10 @@ namespace System.Xaml
                {
                        if (q.IsEmpty)
                                wait.WaitOne ();
+
+                       if (read_exception != null)
+                               read_exception.Throw ();
+
                        return q.Reader.Read ();
                }
                
@@ -105,11 +111,16 @@ namespace System.Xaml
                        if (thread != null)
                                throw new InvalidOperationException ("Thread has already started");
                        thread = new Thread (new ParameterizedThreadStart (delegate {
-                               while (do_work && r.Read ()) {
-                                       q.Writer.WriteNode (r);
+                               try {
+                                       while (do_work && r.Read ()) {
+                                               q.Writer.WriteNode (r);
+                                               wait.Set ();
+                                       }
+                                       read_all_done = true;
+                               } catch (Exception ex) {
+                                       read_exception = ExceptionDispatchInfo.Capture (ex);
                                        wait.Set ();
                                }
-                               read_all_done = true;
                        })) { Name = threadName };
                        thread.Start ();
                }