Skip to content

Commit 3f9b165

Browse files
committed
Break loop if disposed.
1 parent 45b3c96 commit 3f9b165

File tree

1 file changed

+192
-188
lines changed

1 file changed

+192
-188
lines changed
Lines changed: 192 additions & 188 deletions
Original file line numberDiff line numberDiff line change
@@ -1,189 +1,193 @@
1-
// RuntimeInvokeManager.cs
2-
//
3-
// Author:
4-
// Lluis Sanchez Gual <[email protected]>
5-
//
6-
// Copyright (c) 2008 Novell, Inc (http://www.novell.com)
7-
//
8-
// Permission is hereby granted, free of charge, to any person obtaining a copy
9-
// of this software and associated documentation files (the "Software"), to deal
10-
// in the Software without restriction, including without limitation the rights
11-
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12-
// copies of the Software, and to permit persons to whom the Software is
13-
// furnished to do so, subject to the following conditions:
14-
//
15-
// The above copyright notice and this permission notice shall be included in
16-
// all copies or substantial portions of the Software.
17-
//
18-
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19-
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20-
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21-
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22-
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23-
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24-
// THE SOFTWARE.
25-
//
26-
//
27-
28-
using System;
29-
using System.Collections.Generic;
30-
using System.Linq;
31-
using System.Threading.Tasks;
32-
using Mono.Debugging.Client;
33-
34-
namespace Mono.Debugging.Evaluation
35-
{
36-
public class AsyncOperationManager : IDisposable
37-
{
38-
readonly HashSet<IAsyncOperationBase> currentOperations = new HashSet<IAsyncOperationBase> ();
39-
bool disposed = false;
40-
const int ShortCancelTimeout = 100;
41-
42-
static bool IsOperationCancelledException (Exception e, int depth = 4)
43-
{
44-
if (e is OperationCanceledException)
45-
return true;
46-
var aggregateException = e as AggregateException;
47-
48-
if (depth > 0 && aggregateException != null) {
49-
foreach (var innerException in aggregateException.InnerExceptions) {
50-
if (IsOperationCancelledException (innerException, depth - 1))
51-
return true;
52-
}
53-
}
54-
return false;
55-
}
56-
57-
public OperationResult<TValue> Invoke<TValue> (AsyncOperationBase<TValue> mc, int timeout)
58-
{
59-
if (timeout <= 0)
60-
throw new ArgumentOutOfRangeException("timeout", timeout, "timeout must be greater than 0");
61-
62-
Task<OperationResult<TValue>> task;
63-
var description = mc.Description;
64-
lock (currentOperations) {
65-
if (disposed)
66-
throw new ObjectDisposedException ("Already disposed");
67-
DebuggerLoggingService.LogMessage (string.Format("Starting invoke for {0}", description));
68-
task = mc.InvokeAsync ();
69-
currentOperations.Add (mc);
70-
}
71-
72-
bool cancelledAfterTimeout = false;
73-
try {
74-
if (task.Wait (timeout)) {
75-
DebuggerLoggingService.LogMessage (string.Format ("Invoke {0} succeeded in {1} ms", description, timeout));
76-
return task.Result;
77-
}
78-
DebuggerLoggingService.LogMessage (string.Format ("Invoke {0} timed out after {1} ms. Cancelling.", description, timeout));
79-
mc.Abort ();
80-
try {
81-
WaitAfterCancel (mc);
82-
}
83-
catch (Exception e) {
84-
if (IsOperationCancelledException (e)) {
85-
DebuggerLoggingService.LogMessage (string.Format ("Invoke {0} was cancelled after timeout", description));
86-
cancelledAfterTimeout = true;
87-
}
88-
throw;
89-
}
90-
DebuggerLoggingService.LogMessage (string.Format ("{0} cancelling timed out", description));
91-
throw new TimeOutException ();
92-
}
93-
catch (Exception e) {
94-
if (IsOperationCancelledException (e)) {
95-
if (cancelledAfterTimeout)
96-
throw new TimeOutException ();
97-
DebuggerLoggingService.LogMessage (string.Format ("Invoke {0} was cancelled outside before timeout", description));
98-
throw new EvaluatorAbortedException ();
99-
}
100-
throw;
101-
}
102-
finally {
103-
lock (currentOperations) {
104-
currentOperations.Remove (mc);
105-
}
106-
}
107-
}
108-
109-
110-
public event EventHandler<BusyStateEventArgs> BusyStateChanged = delegate { };
111-
112-
void ChangeBusyState (bool busy, string description)
113-
{
114-
try {
115-
BusyStateChanged (this, new BusyStateEventArgs {IsBusy = busy, Description = description});
116-
}
117-
catch (Exception e) {
118-
DebuggerLoggingService.LogError ("Exception during ChangeBusyState", e);
119-
}
120-
}
121-
122-
void WaitAfterCancel (IAsyncOperationBase op)
123-
{
124-
var desc = op.Description;
125-
DebuggerLoggingService.LogMessage (string.Format ("Waiting for cancel of invoke {0}", desc));
126-
if (!op.RawTask.Wait (ShortCancelTimeout)) {
127-
try {
128-
ChangeBusyState (true, desc);
129-
while (true) {
130-
op.Abort ();
131-
if (op.RawTask.Wait (ShortCancelTimeout))
132-
break;
133-
}
134-
}
135-
finally {
136-
ChangeBusyState (false, desc);
137-
}
138-
}
139-
}
140-
141-
public void AbortAll ()
142-
{
143-
DebuggerLoggingService.LogMessage ("Aborting all the current invocations");
144-
List<IAsyncOperationBase> copy;
145-
lock (currentOperations) {
146-
if (disposed) throw new ObjectDisposedException ("Already disposed");
147-
copy = currentOperations.ToList ();
148-
currentOperations.Clear ();
149-
}
150-
151-
CancelOperations (copy, true);
152-
}
153-
154-
void CancelOperations (List<IAsyncOperationBase> operations, bool wait)
155-
{
156-
foreach (var operation in operations) {
157-
var taskDescription = operation.Description;
158-
try {
159-
operation.Abort ();
160-
if (wait) {
161-
WaitAfterCancel (operation);
162-
}
163-
}
164-
catch (Exception e) {
165-
if (IsOperationCancelledException (e)) {
166-
DebuggerLoggingService.LogMessage (string.Format ("Invocation of {0} cancelled in CancelOperations()", taskDescription));
167-
}
168-
else {
169-
DebuggerLoggingService.LogError (string.Format ("Invocation of {0} thrown an exception in CancelOperations()", taskDescription), e);
170-
}
171-
}
172-
}
173-
}
174-
175-
176-
public void Dispose ()
177-
{
178-
List<IAsyncOperationBase> copy;
179-
lock (currentOperations) {
180-
if (disposed) throw new ObjectDisposedException ("Already disposed");
181-
disposed = true;
182-
copy = currentOperations.ToList ();
183-
currentOperations.Clear ();
184-
}
185-
// don't wait on dispose
186-
CancelOperations (copy, wait: false);
187-
}
188-
}
1+
// RuntimeInvokeManager.cs
2+
//
3+
// Author:
4+
// Lluis Sanchez Gual <[email protected]>
5+
//
6+
// Copyright (c) 2008 Novell, Inc (http://www.novell.com)
7+
//
8+
// Permission is hereby granted, free of charge, to any person obtaining a copy
9+
// of this software and associated documentation files (the "Software"), to deal
10+
// in the Software without restriction, including without limitation the rights
11+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
// copies of the Software, and to permit persons to whom the Software is
13+
// furnished to do so, subject to the following conditions:
14+
//
15+
// The above copyright notice and this permission notice shall be included in
16+
// all copies or substantial portions of the Software.
17+
//
18+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
// THE SOFTWARE.
25+
//
26+
//
27+
28+
using System;
29+
using System.Collections.Generic;
30+
using System.Linq;
31+
using System.Threading.Tasks;
32+
using Mono.Debugging.Client;
33+
34+
namespace Mono.Debugging.Evaluation
35+
{
36+
public class AsyncOperationManager : IDisposable
37+
{
38+
readonly HashSet<IAsyncOperationBase> currentOperations = new HashSet<IAsyncOperationBase> ();
39+
bool disposed = false;
40+
const int ShortCancelTimeout = 100;
41+
42+
static bool IsOperationCancelledException (Exception e, int depth = 4)
43+
{
44+
if (e is OperationCanceledException)
45+
return true;
46+
var aggregateException = e as AggregateException;
47+
48+
if (depth > 0 && aggregateException != null) {
49+
foreach (var innerException in aggregateException.InnerExceptions) {
50+
if (IsOperationCancelledException (innerException, depth - 1))
51+
return true;
52+
}
53+
}
54+
return false;
55+
}
56+
57+
public OperationResult<TValue> Invoke<TValue> (AsyncOperationBase<TValue> mc, int timeout)
58+
{
59+
if (timeout <= 0)
60+
throw new ArgumentOutOfRangeException("timeout", timeout, "timeout must be greater than 0");
61+
62+
Task<OperationResult<TValue>> task;
63+
var description = mc.Description;
64+
lock (currentOperations) {
65+
if (disposed)
66+
throw new ObjectDisposedException ("Already disposed");
67+
DebuggerLoggingService.LogMessage (string.Format("Starting invoke for {0}", description));
68+
task = mc.InvokeAsync ();
69+
currentOperations.Add (mc);
70+
}
71+
72+
bool cancelledAfterTimeout = false;
73+
try {
74+
if (task.Wait (timeout)) {
75+
DebuggerLoggingService.LogMessage (string.Format ("Invoke {0} succeeded in {1} ms", description, timeout));
76+
return task.Result;
77+
}
78+
DebuggerLoggingService.LogMessage (string.Format ("Invoke {0} timed out after {1} ms. Cancelling.", description, timeout));
79+
mc.Abort ();
80+
try {
81+
WaitAfterCancel (mc);
82+
}
83+
catch (Exception e) {
84+
if (IsOperationCancelledException (e)) {
85+
DebuggerLoggingService.LogMessage (string.Format ("Invoke {0} was cancelled after timeout", description));
86+
cancelledAfterTimeout = true;
87+
}
88+
throw;
89+
}
90+
DebuggerLoggingService.LogMessage (string.Format ("{0} cancelling timed out", description));
91+
throw new TimeOutException ();
92+
}
93+
catch (Exception e) {
94+
if (IsOperationCancelledException (e)) {
95+
if (cancelledAfterTimeout)
96+
throw new TimeOutException ();
97+
DebuggerLoggingService.LogMessage (string.Format ("Invoke {0} was cancelled outside before timeout", description));
98+
throw new EvaluatorAbortedException ();
99+
}
100+
throw;
101+
}
102+
finally {
103+
lock (currentOperations) {
104+
currentOperations.Remove (mc);
105+
}
106+
}
107+
}
108+
109+
110+
public event EventHandler<BusyStateEventArgs> BusyStateChanged = delegate { };
111+
112+
void ChangeBusyState (bool busy, string description)
113+
{
114+
try {
115+
BusyStateChanged (this, new BusyStateEventArgs {IsBusy = busy, Description = description});
116+
}
117+
catch (Exception e) {
118+
DebuggerLoggingService.LogError ("Exception during ChangeBusyState", e);
119+
}
120+
}
121+
122+
void WaitAfterCancel (IAsyncOperationBase op)
123+
{
124+
var desc = op.Description;
125+
DebuggerLoggingService.LogMessage (string.Format ("Waiting for cancel of invoke {0}", desc));
126+
if (!op.RawTask.Wait (ShortCancelTimeout)) {
127+
try {
128+
ChangeBusyState (true, desc);
129+
while (true) {
130+
lock (currentOperations) {
131+
if (disposed)
132+
break;
133+
}
134+
op.Abort ();
135+
if (op.RawTask.Wait (ShortCancelTimeout))
136+
break;
137+
}
138+
}
139+
finally {
140+
ChangeBusyState (false, desc);
141+
}
142+
}
143+
}
144+
145+
public void AbortAll ()
146+
{
147+
DebuggerLoggingService.LogMessage ("Aborting all the current invocations");
148+
List<IAsyncOperationBase> copy;
149+
lock (currentOperations) {
150+
if (disposed) throw new ObjectDisposedException ("Already disposed");
151+
copy = currentOperations.ToList ();
152+
currentOperations.Clear ();
153+
}
154+
155+
CancelOperations (copy, true);
156+
}
157+
158+
void CancelOperations (List<IAsyncOperationBase> operations, bool wait)
159+
{
160+
foreach (var operation in operations) {
161+
var taskDescription = operation.Description;
162+
try {
163+
operation.Abort ();
164+
if (wait) {
165+
WaitAfterCancel (operation);
166+
}
167+
}
168+
catch (Exception e) {
169+
if (IsOperationCancelledException (e)) {
170+
DebuggerLoggingService.LogMessage (string.Format ("Invocation of {0} cancelled in CancelOperations()", taskDescription));
171+
}
172+
else {
173+
DebuggerLoggingService.LogError (string.Format ("Invocation of {0} thrown an exception in CancelOperations()", taskDescription), e);
174+
}
175+
}
176+
}
177+
}
178+
179+
180+
public void Dispose ()
181+
{
182+
List<IAsyncOperationBase> copy;
183+
lock (currentOperations) {
184+
if (disposed) throw new ObjectDisposedException ("Already disposed");
185+
disposed = true;
186+
copy = currentOperations.ToList ();
187+
currentOperations.Clear ();
188+
}
189+
// don't wait on dispose
190+
CancelOperations (copy, wait: false);
191+
}
192+
}
189193
}

0 commit comments

Comments
 (0)