[runtime] Fix detecting abort at end of abort protected block
[mono.git] / mono / tests / abort-cctor.cs
1 using System;
2 using System.Diagnostics;
3 using System.Threading;
4 using System.Runtime.CompilerServices;
5
6 class Driver
7 {
8         public static ManualResetEvent mre1 = new ManualResetEvent (false);
9         public static ManualResetEvent mre2 = new ManualResetEvent (false);
10
11         class StaticConstructor1
12         {
13                 internal static bool gotToEnd, caughtException;
14                 static StaticConstructor1 ()
15                 {
16                         try {
17                                 Console.WriteLine ("StaticConstructor1.StaticConstructor1 (1)");
18                                 Driver.mre1.Set ();
19                                 var sw = Stopwatch.StartNew ();
20                                 Thread.Sleep (1000);
21                                 sw.Stop ();
22                                 typeof (string).GetMethods ();
23                                 //XXX we assume that if we slept less than 900ms we got aborted
24                                 if (sw.ElapsedMilliseconds < 900)
25                                         throw new Exception ("Bad abort broke our sleep");
26                                 Console.WriteLine ("StaticConstructor1.StaticConstructor1 (2) waited {0}", sw.ElapsedMilliseconds);
27                                 gotToEnd = true;
28                         } catch (Exception e) {
29                                 caughtException = true;
30                                 throw;
31                         }
32                 }
33
34                 public static void Init ()
35                 {
36                         Console.WriteLine ("StaticConstructor1.Init");
37                 }
38         }
39
40         [MethodImplAttribute (MethodImplOptions.NoInlining)]
41         static void IsStaticConstructor1Viable () {
42                 new StaticConstructor1 ();
43                 Console.WriteLine ("Did it get to the end? {0} Did it catch an exception {1}", StaticConstructor1.gotToEnd, StaticConstructor1.caughtException);
44                 if (!StaticConstructor1.gotToEnd) /* the TAE must not land during a .cctor */
45                         Environment.Exit (1);
46                 if (StaticConstructor1.caughtException)
47                         Environment.Exit (2);
48                         
49         }
50
51         static void Test1 ()
52         {
53                 Console.WriteLine ("Test 1:");
54
55                 Driver.mre1.Reset ();
56                 Driver.mre2.Reset ();
57
58                 Thread thread = new Thread (() => {
59                         try {
60                                 StaticConstructor1.Init ();
61                         } catch (Exception e) {
62                                 Console.WriteLine ("StaticConstructor1::init caught exception {0}", e);
63
64                                 if (!(e is ThreadAbortException))
65                                         throw;
66                         }
67                 });
68
69                 thread.Start ();
70
71                 Driver.mre1.WaitOne ();
72
73                 // The ThreadAbortException should land while in
74                 // the StaticConstructor1.cctor. The exception should
75                 // be queued, and be rethrown when exiting the cctor.
76                 thread.Abort ();
77
78                 thread.Join ();
79
80                 //is StaticConstructor1 viable?
81                 try {
82                         IsStaticConstructor1Viable ();
83                         Console.WriteLine ("StaticConstructor1 is viable"); /* a TAE doesn't make a type unusable */
84                 } catch (TypeInitializationException  e) {
85                         Console.WriteLine ("StaticConstructor1 not viable");
86                         Environment.Exit (3);
87                 }
88         }
89
90         class StaticConstructor2Exception : Exception {}
91
92         class StaticConstructor2
93         {
94                 static StaticConstructor2 ()
95                 {
96                         Console.WriteLine ("StaticConstructor2.StaticConstructor2 (1)");
97                         Driver.mre1.Set ();
98                         throw new StaticConstructor2Exception ();
99                         /* Unreachable */
100                         Driver.mre2.Set ();
101                         Console.WriteLine ("StaticConstructor2.StaticConstructor2 (2)");
102                 }
103
104                 public static void Init ()
105                 {
106                         Console.WriteLine ("StaticConstructor2.Init");
107                 }
108         }
109
110         [MethodImplAttribute (MethodImplOptions.NoInlining)]
111         static void IsStaticConstructor2Viable () {
112                 new StaticConstructor2 ();
113         }
114
115
116         static void Test2 ()
117         {
118                 Console.WriteLine ("Test 2:");
119
120                 Driver.mre1.Reset ();
121                 Driver.mre2.Reset ();
122
123                 Thread thread = new Thread (() => {
124                         try {
125                                 StaticConstructor2.Init ();
126                         } catch (TypeInitializationException e) {
127                                 Console.WriteLine (e);
128
129                                 if (!(e.InnerException is StaticConstructor2Exception))
130                                         throw;
131                         }
132                 });
133
134                 thread.Start ();
135
136                 Driver.mre1.WaitOne ();
137
138                 // A InvalidOperationException should be thrown while in
139                 // the StaticConstructor2.cctor. The exception should
140                 // be wrapped in a TypeInitializationException.
141
142                 if (Driver.mre2.WaitOne (500)) {
143                         /* We shouldn't reach Driver.mre.Set () in StaticConstructor2.cctor */
144                         Environment.Exit (4);
145                 }
146
147                 thread.Join ();
148
149                 //is StaticConstructor2 viable?
150                 try {
151                         IsStaticConstructor2Viable ();
152                         Console.WriteLine ("StaticConstructor2 is viable");
153                         /* A regular exception escaping the .cctor makes the type not usable */
154                         Environment.Exit (5);
155                 } catch (TypeInitializationException e) {
156                         Console.WriteLine ("StaticConstructor2 not viable");
157                 }
158
159         }
160
161         class StaticConstructor3
162         {
163                 static StaticConstructor3 ()
164                 {
165                         Console.WriteLine ("StaticConstructor3.StaticConstructor3 (1)");
166                         Driver.mre1.Set ();
167                         Thread.CurrentThread.Abort ();
168                         /* Unreachable */
169                         Driver.mre2.Set ();
170                         Console.WriteLine ("StaticConstructor3.StaticConstructor3 (2)");
171                         Environment.Exit (6);
172                 }
173
174                 public static void Init ()
175                 {
176                         Console.WriteLine ("StaticConstructor3.Init");
177                 }
178         }
179
180         [MethodImplAttribute (MethodImplOptions.NoInlining)]
181         static void IsStaticConstructor3Viable () {
182                 new StaticConstructor3 ();
183         }
184
185         static void Test3 ()
186         {
187                 Console.WriteLine ("Test 3:");
188                 bool catched_abort = false;
189
190                 Driver.mre1.Reset ();
191                 Driver.mre2.Reset ();
192
193                 Thread thread = new Thread (() => {
194                         try {
195                                 StaticConstructor3.Init ();
196                                 Console.WriteLine ("cctor3 didn't throw?!?!");
197                                 /* StaticConstructor3 self aborted */
198                                 Environment.Exit (7);
199                         } catch (ThreadAbortException e) {
200                                 Console.WriteLine ("TEST 3: aborted {0}", e);
201                                 catched_abort = true;
202                         }
203                 });
204
205                 thread.Start ();
206
207                 Driver.mre1.WaitOne ();
208
209                 // A InvalidOperationException should be thrown while in
210                 // the StaticConstructor2.cctor. The exception should
211                 // be wrapped in a TypeInitializationException.
212
213                 thread.Join ();
214
215                 // Did we catch the abort
216                 if (!catched_abort)
217                         Environment.Exit (8);
218
219                 //is StaticConstructor2 viable?
220                 try {
221                         IsStaticConstructor3Viable ();
222                         Console.WriteLine ("StaticConstructor3 is viable");
223                         /* A regular exception escaping the .cctor makes the type not usable */
224                         Environment.Exit (9);
225                 } catch (TypeInitializationException e) {
226                         Console.WriteLine ("StaticConstructor3 not viable");
227                 }
228         }
229
230
231
232
233
234         class StaticConstructor4
235         {
236                 internal static bool gotToEnd, caughtException;
237
238                 static StaticConstructor4 ()
239                 {
240                         try {
241                                 Console.WriteLine ("StaticConstructor4.StaticConstructor4 (1)");
242                                 Driver.mre1.Set ();
243                                 var sw = Stopwatch.StartNew ();
244                                 Thread.Sleep (1000);
245                                 sw.Stop ();
246                                 typeof (string).GetMethods ();
247                                 //XXX we assume that if we slept less than 900ms we got aborted
248                                 if (sw.ElapsedMilliseconds < 900)
249                                         throw new Exception ("Bad abort broke our sleep");
250                                 Console.WriteLine ("StaticConstructor4.StaticConstructor4 (2) waited {0}", sw.ElapsedMilliseconds);
251                                 gotToEnd = true;
252                         } catch (Exception e) {
253                                 caughtException = true;
254                                 throw;
255                         }       
256                 }
257
258                 public static void Init ()
259                 {
260                         Console.WriteLine ("StaticConstructor4.Init");
261                 }
262         }
263
264         static bool got_to_the_end_of_the_finally = false;
265
266         [MethodImplAttribute (MethodImplOptions.NoInlining)]
267         static void IsStaticConstructor4Viable () {
268                 new StaticConstructor4 ();
269                 Console.WriteLine ("IsStaticConstructor4Viable: Did it get to the end? {0} Did it catch an exception {1} and end of the finally block {2}", StaticConstructor4.gotToEnd, StaticConstructor4.caughtException, got_to_the_end_of_the_finally);
270                 if (!StaticConstructor4.gotToEnd) /* the TAE must not land during a .cctor */
271                         Environment.Exit (10);
272                 if (StaticConstructor4.caughtException)
273                         Environment.Exit (11);
274         }
275
276         static void Test4 ()
277         {
278                 Console.WriteLine ("Test 4:");
279
280                 Driver.mre1.Reset ();
281                 Driver.mre2.Reset ();
282
283                 Thread thread = new Thread (() => {
284                         try {
285
286                                 try {
287                                 } finally {
288                                         StaticConstructor4.Init ();
289                                         Console.WriteLine ("Test 4: After the cctor");
290                                         got_to_the_end_of_the_finally = true;
291                                 }
292                         } catch (Exception e) {
293                                 Console.WriteLine ("StaticConstructor4::init caught exception {0}", e);
294                                 if (!(e is ThreadAbortException))
295                                         throw;
296                                 if (!got_to_the_end_of_the_finally)
297                                         throw new Exception ("Test 4: did not get to the end of the cctor");
298                         }
299                 });
300
301                 thread.Start ();
302
303                 Driver.mre1.WaitOne ();
304
305                 // The ThreadAbortException should land while in
306                 // the StaticConstructor4.cctor. The exception should
307                 // be queued, and be rethrown when exiting the cctor.
308                 thread.Abort ();
309
310                 thread.Join ();
311
312                 if (!got_to_the_end_of_the_finally) { 
313                         Console.WriteLine ("Did not get to the end of test 4 cctor");
314                         Environment.Exit (12);
315                 }
316
317                 //is StaticConstructor4viable?
318                 try {
319                         IsStaticConstructor4Viable ();
320                         Console.WriteLine ("StaticConstructor4 is viable"); /* a TAE doesn't make a type unusable */
321                 } catch (TypeInitializationException  e) {
322                         Console.WriteLine ("StaticConstructor4 not viable");
323                         Environment.Exit (13);
324                 }
325         }
326
327
328         class StaticConstructor5 {
329                 public static bool catched_exception = false;
330                 static StaticConstructor5 ()
331                 {
332                         Driver.mre1.Set ();
333                         Driver.mre2.WaitOne ();
334                         try {
335                                 throw new Exception ();
336                         } catch (Exception) {
337                                 Console.WriteLine ("Catched exception in cctor");
338                                 catched_exception = true;
339                         }
340                 }
341         }
342
343         static void Test5 ()
344         {
345                 bool catched_abort = false;
346                 Driver.mre1.Reset ();
347                 Driver.mre2.Reset ();
348                 Thread thread = new Thread (() => {
349                                         try {
350                                                 new StaticConstructor5 ();
351                                         } catch (ThreadAbortException) {
352                                                 Console.WriteLine ("Catched thread abort");
353                                                 catched_abort = true;
354                                         }
355                                 });
356                 thread.Start ();
357
358                 Driver.mre1.WaitOne ();
359                 thread.Abort ();
360                 Driver.mre2.Set ();
361
362                 thread.Join ();
363
364                 if (!StaticConstructor5.catched_exception)
365                         Environment.Exit (14);
366                 if (!catched_abort)
367                         Environment.Exit (15);
368         }
369
370         public static int Main ()
371         {
372                 Test1 ();
373                 Test2 ();
374                 Test3 ();
375                 Test4 ();
376                 Test5 ();
377                 Console.WriteLine ("done, all things good");
378                 return 0;
379         }
380 }