Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/monodevelop.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/main
diff options
context:
space:
mode:
authorLluis Sanchez <llsan@microsoft.com>2019-03-08 21:59:16 +0300
committerLluis Sanchez <llsan@microsoft.com>2019-03-08 21:59:16 +0300
commitd2566c3f41e9326b2ce121bbdbdd762896cbcc80 (patch)
tree83f954e96bd91af530f3cdeb37f2192f3487b325 /main
parentd9b2683518bca9d8e6cdd067d1726ed1faf4612d (diff)
parent789eb8dccef5fd4d4b35a2c2a44ef743f0217bd3 (diff)
Merge remote-tracking branch 'origin/release-8.0-integration' into merge-integration-11
Diffstat (limited to 'main')
-rw-r--r--main/src/addins/MonoDevelop.SourceEditor2/MonoDevelop.SourceEditor/SourceEditorView.cs5
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/AsyncCriticalSection.cs8
-rw-r--r--main/tests/MonoDevelop.Core.Tests/MonoDevelop.Core.Tests.csproj1
-rw-r--r--main/tests/MonoDevelop.Core.Tests/MonoDevelop.Projects/AsyncCriticalSectionTests.cs78
4 files changed, 89 insertions, 3 deletions
diff --git a/main/src/addins/MonoDevelop.SourceEditor2/MonoDevelop.SourceEditor/SourceEditorView.cs b/main/src/addins/MonoDevelop.SourceEditor2/MonoDevelop.SourceEditor/SourceEditorView.cs
index 020f46d3bd..3f675e740f 100644
--- a/main/src/addins/MonoDevelop.SourceEditor2/MonoDevelop.SourceEditor/SourceEditorView.cs
+++ b/main/src/addins/MonoDevelop.SourceEditor2/MonoDevelop.SourceEditor/SourceEditorView.cs
@@ -1487,8 +1487,9 @@ namespace MonoDevelop.SourceEditor
} else if (args.Button == 1) {
if (!string.IsNullOrEmpty (Document.FileName)) {
if (args.LineSegment != null) {
- int column = TextEditor.Caret.Line == args.LineNumber ? TextEditor.Caret.Column : 1;
-
+ int column = TextEditor.Caret.Line == args.LineNumber ?
+ Math.Min (TextEditor.Caret.Column, args.LineSegment.Length) : 1;
+
lock (breakpoints)
breakpoints.Toggle (Document.FileName, args.LineNumber, column);
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/AsyncCriticalSection.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/AsyncCriticalSection.cs
index 98c6874003..78d8b18fa5 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/AsyncCriticalSection.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/AsyncCriticalSection.cs
@@ -67,7 +67,13 @@ namespace MonoDevelop.Projects
locked = true;
return Task.FromResult (criticalSectionDisposer);
}
- var s = new TaskCompletionSource<IDisposable> ();
+
+ // When the TaskCompletionSource's SetResult method is called then all the async continuations waiting
+ // on this lock may be invoked synchronously. This can cause a stack overflow if many tasks are queued.
+ // To avoid this the continuations are run asynchronously by creating the TaskCompletionSource with
+ // TaskCreationOptions.RunContinuationsAsynchronously.
+ // https://stackoverflow.com/questions/28321457/taskcontinuationoptions-runcontinuationsasynchronously-and-stack-dives
+ var s = new TaskCompletionSource<IDisposable> (TaskCreationOptions.RunContinuationsAsynchronously);
queue.Enqueue (s);
return s.Task;
}
diff --git a/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Core.Tests.csproj b/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Core.Tests.csproj
index f556b66d0d..97762a7653 100644
--- a/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Core.Tests.csproj
+++ b/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Core.Tests.csproj
@@ -117,6 +117,7 @@
<Compile Include="MonoDevelop.Core\SdkResolverTests.cs" />
<Compile Include="MonoDevelop.Core\FileServiceEventQueueTests.cs" />
<Compile Include="MonoDevelop.Core\FileServiceEventStateMachineTests.cs" />
+ <Compile Include="MonoDevelop.Projects\AsyncCriticalSectionTests.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\core\MonoDevelop.Core\MonoDevelop.Core.csproj">
diff --git a/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Projects/AsyncCriticalSectionTests.cs b/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Projects/AsyncCriticalSectionTests.cs
new file mode 100644
index 0000000000..3406f814e1
--- /dev/null
+++ b/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Projects/AsyncCriticalSectionTests.cs
@@ -0,0 +1,78 @@
+//
+// AsyncCriticalSectionTests.cs
+//
+// Author:
+// Matt Ward <matt.ward@microsoft.com>
+//
+// Copyright (c) 2019 Microsoft
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using NUnit.Framework;
+
+namespace MonoDevelop.Projects
+{
+ [TestFixture]
+ public class AsyncCriticalSectionTests
+ {
+ AsyncCriticalSection referenceCacheLock;
+ ManualResetEvent unlockEvent;
+ ManualResetEvent doneEvent;
+ const int maxLoadProjectCalls = 10000;
+
+ [Test]
+ public void StackOverflowTest ()
+ {
+ referenceCacheLock = new AsyncCriticalSection ();
+ unlockEvent = new ManualResetEvent (false);
+ doneEvent = new ManualResetEvent (false);
+
+ for (int i = 0; i < maxLoadProjectCalls; ++i) {
+ Run (i);
+ }
+
+ Thread.Sleep (500);
+
+ unlockEvent.Set ();
+ bool result = doneEvent.WaitOne (5000);
+ if (!result)
+ Assert.Fail ("Done event not fired.");
+ }
+
+ void Run (int i)
+ {
+ Task.Run (async () => {
+ await LoadProject (i);
+ });
+ }
+
+ async Task LoadProject (int i)
+ {
+ using (await referenceCacheLock.EnterAsync ().ConfigureAwait (false)) {
+ unlockEvent.WaitOne ();
+
+ if (i == maxLoadProjectCalls - 1)
+ doneEvent.Set ();
+ }
+ }
+ }
+}