Merge pull request #1899 from saper/resgencond
[mono.git] / mcs / class / System.Core / Test / System.Threading / ReaderWriterLockSlimTest.cs
1 //
2 // ReaderWriterLockSlimTest.cs
3 //
4 // Authors:
5 //      Marek Safar (marek.safar@gmail.com)
6 //
7 // Copyright (C) 2009 Novell, Inc (http://www.novell.com)
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28
29 using System;
30 using NUnit.Framework;
31 using System.Threading;
32 using System.Linq;
33 using System.Threading.Tasks;
34
35 namespace MonoTests.System.Threading
36 {
37         [TestFixture]
38         public class ReaderWriterLockSlimTests
39         {
40                 [Test]
41                 public void DefaultValues ()
42                 {
43                         var v = new ReaderWriterLockSlim ();
44                         Assert.AreEqual (0, v.CurrentReadCount, "1");
45                         Assert.AreEqual (false, v.IsReadLockHeld, "2");
46                         Assert.AreEqual (false, v.IsUpgradeableReadLockHeld, "3");
47                         Assert.AreEqual (false, v.IsWriteLockHeld, "4");
48                         Assert.AreEqual (LockRecursionPolicy.NoRecursion, v.RecursionPolicy, "5");
49                         Assert.AreEqual (0, v.RecursiveReadCount, "6");
50                         Assert.AreEqual (0, v.RecursiveUpgradeCount, "7");
51                         Assert.AreEqual (0, v.RecursiveWriteCount, "8");
52                         Assert.AreEqual (0, v.WaitingReadCount, "9");
53                         Assert.AreEqual (0, v.WaitingUpgradeCount, "10");
54                         Assert.AreEqual (0, v.WaitingWriteCount, "11");
55                 }
56
57                 [Test]
58                 public void Dispose_Errors ()
59                 {
60                         var v = new ReaderWriterLockSlim ();
61                         v.Dispose ();
62
63                         try {
64                                 v.EnterUpgradeableReadLock ();
65                                 Assert.Fail ("1");
66                         } catch (ObjectDisposedException) {
67                         }
68
69                         try {
70                                 v.EnterReadLock ();
71                                 Assert.Fail ("2");
72                         } catch (ObjectDisposedException) {
73                         }
74
75                         try {
76                                 v.EnterWriteLock ();
77                                 Assert.Fail ("3");
78                         } catch (ObjectDisposedException) {
79                         }
80                 }
81
82                 [Test]
83                 public void Dispose_WithReadLock ()
84                 {
85                         var rwl = new ReaderWriterLockSlim ();
86                         rwl.EnterReadLock ();
87                         try {
88                                 rwl.Dispose ();
89                                 Assert.Fail ("1");
90                         } catch (SynchronizationLockException) {
91                         }
92                 }
93
94                 [Test]
95                 public void Dispose_WithWriteLock ()
96                 {
97                         var rwl = new ReaderWriterLockSlim ();
98                         rwl.EnterWriteLock ();
99                         try {
100                                 rwl.Dispose ();
101                                 Assert.Fail ("1");
102                         } catch (SynchronizationLockException) {
103                         }
104                 }
105
106                 [Test]
107                 public void Dispose_UpgradeableReadLock ()
108                 {
109                         var rwl = new ReaderWriterLockSlim ();
110                         rwl.EnterUpgradeableReadLock ();
111                         try {
112                                 rwl.Dispose ();
113                                 Assert.Fail ("1");
114                         } catch (SynchronizationLockException) {
115                         }
116                 }
117
118                 [Test]
119                 public void TryEnterReadLock_OutOfRange ()
120                 {
121                         var v = new ReaderWriterLockSlim ();
122                         try {
123                                 v.TryEnterReadLock (-2);
124                                 Assert.Fail ("1");
125                         } catch (ArgumentOutOfRangeException) {
126                         }
127
128                         try {
129                                 v.TryEnterReadLock (TimeSpan.MaxValue);
130                                 Assert.Fail ("2");
131                         } catch (ArgumentOutOfRangeException) {
132                         }
133
134                         try {
135                                 v.TryEnterReadLock (TimeSpan.MinValue);
136                                 Assert.Fail ("3");
137                         } catch (ArgumentOutOfRangeException) {
138                         }
139                 }
140
141                 [Test]
142                 public void TryEnterUpgradeableReadLock_OutOfRange ()
143                 {
144                         var v = new ReaderWriterLockSlim ();
145                         try {
146                                 v.TryEnterUpgradeableReadLock (-2);
147                                 Assert.Fail ("1");
148                         } catch (ArgumentOutOfRangeException) {
149                         }
150
151                         try {
152                                 v.TryEnterUpgradeableReadLock (TimeSpan.MaxValue);
153                                 Assert.Fail ("2");
154                         } catch (ArgumentOutOfRangeException) {
155                         }
156
157                         try {
158                                 v.TryEnterUpgradeableReadLock (TimeSpan.MinValue);
159                                 Assert.Fail ("3");
160                         } catch (ArgumentOutOfRangeException) {
161                         }
162                 }
163
164                 [Test]
165                 public void TryEnterWriteLock_OutOfRange ()
166                 {
167                         var v = new ReaderWriterLockSlim ();
168                         try {
169                                 v.TryEnterWriteLock (-2);
170                                 Assert.Fail ("1");
171                         } catch (ArgumentOutOfRangeException) {
172                         }
173
174                         try {
175                                 v.TryEnterWriteLock (TimeSpan.MaxValue);
176                                 Assert.Fail ("2");
177                         } catch (ArgumentOutOfRangeException) {
178                         }
179
180                         try {
181                                 v.TryEnterWriteLock (TimeSpan.MinValue);
182                                 Assert.Fail ("3");
183                         } catch (ArgumentOutOfRangeException) {
184                         }
185                 }
186
187                 [Test, ExpectedException (typeof (SynchronizationLockException))]
188                 public void ExitReadLock ()
189                 {
190                         var v = new ReaderWriterLockSlim ();
191                         v.ExitReadLock ();
192                 }
193
194                 [Test, ExpectedException (typeof (SynchronizationLockException))]
195                 public void ExitWriteLock ()
196                 {
197                         var v = new ReaderWriterLockSlim ();
198                         v.ExitWriteLock ();
199                 }
200
201                 [Test]
202                 public void EnterReadLock_NoRecursionError ()
203                 {
204                         var v = new ReaderWriterLockSlim ();
205                         v.EnterReadLock ();
206                         Assert.AreEqual (1, v.RecursiveReadCount);
207
208                         try {
209                                 v.EnterReadLock ();
210                                 Assert.Fail ("1");
211                         } catch (LockRecursionException) {
212                         }
213
214                         try {
215                                 v.EnterWriteLock ();
216                                 Assert.Fail ("2");
217                         } catch (LockRecursionException) {
218                         }
219                 }
220
221                 [Test]
222                 public void EnterReadLock ()
223                 {
224                         var v = new ReaderWriterLockSlim ();
225
226                         v.EnterReadLock ();
227                         Assert.IsTrue (v.IsReadLockHeld, "A");
228                         Assert.AreEqual (0, v.RecursiveWriteCount, "A1");
229                         Assert.AreEqual (1, v.RecursiveReadCount, "A2");
230                         Assert.AreEqual (0, v.RecursiveUpgradeCount, "A3");
231                         Assert.AreEqual (0, v.WaitingReadCount, "A4");
232                         Assert.AreEqual (0, v.WaitingUpgradeCount, "A5");
233                         Assert.AreEqual (0, v.WaitingWriteCount, "A6");
234                         v.ExitReadLock ();
235
236                         v.EnterReadLock ();
237                         Assert.IsTrue (v.IsReadLockHeld, "B");
238                         Assert.AreEqual (0, v.RecursiveWriteCount, "B1");
239                         Assert.AreEqual (1, v.RecursiveReadCount, "B2");
240                         Assert.AreEqual (0, v.RecursiveUpgradeCount, "B3");
241                         Assert.AreEqual (0, v.WaitingReadCount, "B4");
242                         Assert.AreEqual (0, v.WaitingUpgradeCount, "B5");
243                         Assert.AreEqual (0, v.WaitingWriteCount, "B6");
244                         v.ExitReadLock ();
245                 }
246
247                 [Test]
248                 public void EnterWriteLock_NoRecursionError ()
249                 {
250                         var v = new ReaderWriterLockSlim ();
251                         v.EnterWriteLock ();
252                         Assert.AreEqual (1, v.RecursiveWriteCount);
253
254                         try {
255                                 v.EnterWriteLock ();
256                                 Assert.Fail ("1");
257                         } catch (LockRecursionException) {
258                         }
259
260                         try {
261                                 v.EnterReadLock ();
262                                 Assert.Fail ("2");
263                         } catch (LockRecursionException) {
264                         }
265                 }
266
267                 [Test]
268                 public void EnterWriteLock ()
269                 {
270                         var v = new ReaderWriterLockSlim ();
271
272                         v.EnterWriteLock ();
273                         Assert.IsTrue (v.IsWriteLockHeld, "A");
274                         Assert.AreEqual (1, v.RecursiveWriteCount, "A1");
275                         Assert.AreEqual (0, v.RecursiveReadCount, "A2");
276                         Assert.AreEqual (0, v.RecursiveUpgradeCount, "A3");
277                         Assert.AreEqual (0, v.WaitingReadCount, "A4");
278                         Assert.AreEqual (0, v.WaitingUpgradeCount, "A5");
279                         Assert.AreEqual (0, v.WaitingWriteCount, "A6");
280                         v.ExitWriteLock ();
281
282                         v.EnterWriteLock ();
283                         Assert.IsTrue (v.IsWriteLockHeld, "B");
284                         Assert.AreEqual (1, v.RecursiveWriteCount, "B1");
285                         Assert.AreEqual (0, v.RecursiveReadCount, "B2");
286                         Assert.AreEqual (0, v.RecursiveUpgradeCount, "B3");
287                         Assert.AreEqual (0, v.WaitingReadCount, "B4");
288                         Assert.AreEqual (0, v.WaitingUpgradeCount, "B5");
289                         Assert.AreEqual (0, v.WaitingWriteCount, "B6");
290                         v.ExitWriteLock ();
291                 }
292
293                 [Test]
294                 public void EnterUpgradeableReadLock_NoRecursionError ()
295                 {
296                         var v = new ReaderWriterLockSlim ();
297                         v.EnterUpgradeableReadLock ();
298                         Assert.AreEqual (1, v.RecursiveUpgradeCount);
299
300                         try {
301                                 v.EnterUpgradeableReadLock ();
302                                 Assert.Fail ("2");
303                         } catch (LockRecursionException) {
304                         }
305                 }
306
307                 [Test]
308                 public void EnterUpgradeableReadLock ()
309                 {
310                         var v = new ReaderWriterLockSlim ();
311
312                         v.EnterUpgradeableReadLock ();
313                         Assert.IsTrue (v.IsUpgradeableReadLockHeld, "A");
314                         Assert.AreEqual (0, v.RecursiveWriteCount, "A1");
315                         Assert.AreEqual (0, v.RecursiveReadCount, "A2");
316                         Assert.AreEqual (1, v.RecursiveUpgradeCount, "A3");
317                         Assert.AreEqual (0, v.WaitingReadCount, "A4");
318                         Assert.AreEqual (0, v.WaitingUpgradeCount, "A5");
319                         Assert.AreEqual (0, v.WaitingWriteCount, "A6");
320                         v.ExitUpgradeableReadLock ();
321
322                         v.EnterUpgradeableReadLock ();
323                         Assert.IsTrue (v.IsUpgradeableReadLockHeld, "B");
324                         Assert.AreEqual (0, v.RecursiveWriteCount, "B1");
325                         Assert.AreEqual (0, v.RecursiveReadCount, "B2");
326                         Assert.AreEqual (1, v.RecursiveUpgradeCount, "B3");
327                         Assert.AreEqual (0, v.WaitingReadCount, "B4");
328                         Assert.AreEqual (0, v.WaitingUpgradeCount, "B5");
329                         Assert.AreEqual (0, v.WaitingWriteCount, "B6");
330
331                         v.EnterReadLock ();
332                         v.ExitUpgradeableReadLock ();
333
334                         Assert.IsTrue (v.IsReadLockHeld, "C");
335                         Assert.AreEqual (0, v.RecursiveWriteCount, "C1");
336                         Assert.AreEqual (1, v.RecursiveReadCount, "C2");
337                         Assert.AreEqual (0, v.RecursiveUpgradeCount, "C3");
338                         Assert.AreEqual (0, v.WaitingReadCount, "C4");
339                         Assert.AreEqual (0, v.WaitingUpgradeCount, "C5");
340                         Assert.AreEqual (0, v.WaitingWriteCount, "C6");
341
342                         v.ExitReadLock ();
343                 }
344
345                 [Test]
346                 public void EnterReadLock_MultiRead ()
347                 {
348                         var v = new ReaderWriterLockSlim ();
349                         int local = 10;
350
351                         var r = from i in Enumerable.Range (1, 30) select new Thread (() => {
352
353                                 // Just to cause some contention
354                                 Thread.Sleep (100);
355
356                                 v.EnterReadLock ();
357
358                                 Assert.AreEqual (10, local);
359                         });
360
361                         var threads = r.ToList ();
362
363                         foreach (var t in threads) {
364                                 t.Start ();
365                         }
366
367                         foreach (var t in threads) {
368                                 // Console.WriteLine (t.ThreadState);
369                                 t.Join ();
370                         }
371                 }
372
373                 [Test]
374                 public void TryEnterWriteLock_WhileReading ()
375                 {
376                         var v = new ReaderWriterLockSlim ();
377                         AutoResetEvent ev = new AutoResetEvent (false);
378                         AutoResetEvent ev2 = new AutoResetEvent (false);
379
380                         Thread t1 = new Thread (() => {
381                                 v.EnterReadLock ();
382                                 ev2.Set ();
383                                 ev.WaitOne ();
384                                 v.ExitReadLock ();
385                         });
386
387                         t1.Start ();
388                         ev2.WaitOne ();
389
390                         Assert.IsFalse (v.TryEnterWriteLock (100));
391                         ev.Set ();
392                         t1.Join ();
393
394                         Assert.IsTrue (v.TryEnterWriteLock (100));
395                 }
396
397                 [Test]
398                 public void EnterWriteLock_MultiRead ()
399                 {
400                         var v = new ReaderWriterLockSlim ();
401                         int local = 10;
402                         int ready_count = 0;
403                         int entered_count = 0;
404                         const int thread_count = 10;
405
406                         var r = from i in Enumerable.Range (1, thread_count) select new Thread (() => {
407                                 Interlocked.Increment (ref ready_count);
408                                 v.EnterReadLock ();
409                                 Interlocked.Increment (ref entered_count);
410
411                                 Assert.AreEqual (11, local);
412                         });
413
414                         v.EnterWriteLock ();
415
416                         var threads = r.ToList ();
417                         foreach (var t in threads) {
418                                 t.Start ();
419                         }
420
421                         while (ready_count != thread_count)
422                                 Thread.Sleep (10);
423
424                         /* Extra up to 2s of sleep to ensure all threads got the chance to enter the lock */
425                         for (int i = 0; i < 200 && v.WaitingReadCount != thread_count; ++i)
426                                 Thread.Sleep (10);
427                         local = 11;
428
429                         Assert.AreEqual (0, v.WaitingWriteCount, "in waiting write");
430                         Assert.AreEqual (thread_count, v.WaitingReadCount, "in waiting read");
431                         Assert.AreEqual (0, v.WaitingUpgradeCount, "in waiting upgrade");
432                         v.ExitWriteLock ();
433
434                         foreach (var t in threads) {
435                                 // Console.WriteLine (t.ThreadState);
436                                 t.Join ();
437                         }
438                 }
439
440                 [Test]
441                 public void EnterWriteLock_After_ExitUpgradeableReadLock ()
442                 {
443                         var v = new ReaderWriterLockSlim ();
444
445                         v.EnterUpgradeableReadLock ();
446                         Assert.IsTrue (v.TryEnterWriteLock (100));
447                         v.ExitWriteLock ();
448                         v.ExitUpgradeableReadLock ();
449                         Assert.IsTrue (v.TryEnterWriteLock (100));
450                         v.ExitWriteLock ();
451                 }
452                 [Test]
453                 public void EnterWriteLockWhileInUpgradeAndOtherWaiting ()
454                 {
455                         var v = new ReaderWriterLockSlim ();
456
457                         var task2 = new Task(() => {
458                 v.EnterWriteLock();
459                 v.ExitWriteLock();
460             });
461
462             var task1 = new Task(() =>
463             {
464                 v.EnterUpgradeableReadLock ();
465                 task2.Start ();
466                 Thread.Sleep (100);
467                 v.EnterWriteLock ();
468                 v.ExitWriteLock ();
469                 v.ExitUpgradeableReadLock ();
470             });
471             task1.Start ();
472
473             Assert.IsTrue (task1.Wait (500));
474                 }
475                 [Test]
476                 public void RecursiveReadLockTest ()
477                 {
478                         var v = new ReaderWriterLockSlim (LockRecursionPolicy.SupportsRecursion);
479
480                         Assert.IsTrue (v.TryEnterReadLock (100), "#1");
481                         Assert.IsTrue (v.TryEnterReadLock (100), "#2");
482                         Assert.IsTrue (v.TryEnterReadLock (100), "#3");
483
484                         Assert.AreEqual (3, v.RecursiveReadCount);
485                 }
486
487                 [Test]
488                 public void RecursiveReadPlusWriteLockTest ()
489                 {
490                         var v = new ReaderWriterLockSlim (LockRecursionPolicy.SupportsRecursion);
491
492                         try {
493                                 v.EnterReadLock ();
494                                 v.EnterWriteLock ();
495                                 Assert.Fail ("1");
496                         } catch (LockRecursionException ex) {
497                                 Assert.IsNotNull (ex, "#1");
498                         }
499                 }
500
501                 [Test]
502                 public void RecursiveReadPlusUpgradeableLockTest ()
503                 {
504                         var v = new ReaderWriterLockSlim (LockRecursionPolicy.SupportsRecursion);
505
506                         try {
507                                 v.EnterReadLock ();
508                                 v.EnterUpgradeableReadLock ();
509                                 Assert.Fail ("1");
510                         } catch (LockRecursionException ex) {
511                                 Assert.IsNotNull (ex, "#1");
512                         }
513                 }
514
515                 [Test]
516                 public void RecursiveWriteLockTest ()
517                 {
518                         var v = new ReaderWriterLockSlim (LockRecursionPolicy.SupportsRecursion);
519
520                         Assert.IsTrue (v.TryEnterWriteLock (100), "#1");
521                         Assert.IsTrue (v.TryEnterWriteLock (100), "#2");
522                         Assert.IsTrue (v.TryEnterWriteLock (100), "#3");
523
524                         Assert.AreEqual (3, v.RecursiveWriteCount);
525                 }
526
527                 [Test]
528                 public void RecursiveWritePlusReadLockTest ()
529                 {
530                         var v = new ReaderWriterLockSlim (LockRecursionPolicy.SupportsRecursion);
531
532                         Assert.IsTrue (v.TryEnterWriteLock (100), "#1");
533                         Assert.AreEqual (1, v.RecursiveWriteCount, "1b");
534                         Assert.AreEqual (0, v.RecursiveReadCount, "1c");
535
536                         Assert.IsTrue (v.TryEnterReadLock (100), "#2");
537                         Assert.AreEqual (1, v.RecursiveWriteCount, "2b");
538                         Assert.AreEqual (1, v.RecursiveReadCount, "2c");
539
540                         Assert.IsTrue (v.TryEnterReadLock (100), "#3");
541                         Assert.AreEqual (1, v.RecursiveWriteCount, "3b");
542                         Assert.AreEqual (2, v.RecursiveReadCount, "3c");
543
544                         v.ExitReadLock ();
545                         Assert.AreEqual (1, v.RecursiveWriteCount, "4b");
546                         Assert.AreEqual (1, v.RecursiveReadCount, "4c");
547                 }
548
549                 [Test]
550                 public void RecursiveUpgradeableReadLockTest ()
551                 {
552                         var v = new ReaderWriterLockSlim (LockRecursionPolicy.SupportsRecursion);
553
554                         Assert.IsTrue (v.TryEnterUpgradeableReadLock (100), "#1");
555                         Assert.IsTrue (v.TryEnterUpgradeableReadLock (100), "#2");
556                         Assert.IsTrue (v.TryEnterUpgradeableReadLock (100), "#3");
557
558                         Assert.AreEqual (3, v.RecursiveUpgradeCount);
559                 }
560
561                 [Test]
562                 public void RecursiveReadPropertiesTest ()
563                 {
564                         var v = new ReaderWriterLockSlim (LockRecursionPolicy.SupportsRecursion);
565
566                         v.EnterReadLock ();
567                         v.EnterReadLock ();
568
569                         Assert.AreEqual (true, v.IsReadLockHeld, "#1a");
570                         Assert.AreEqual (1, v.CurrentReadCount, "#2a");
571                         Assert.AreEqual (2, v.RecursiveReadCount, "#3a");
572
573                         bool rLock = true;
574                         int cReadCount = -1, rReadCount = -1;
575
576                         Thread t = new Thread ((_) => {
577                                         rLock = v.IsReadLockHeld;
578                                         cReadCount = v.CurrentReadCount;
579                                         rReadCount = v.RecursiveReadCount;
580                                 });
581
582                         t.Start ();
583                         t.Join ();
584
585                         Assert.AreEqual (false, rLock, "#1b");
586                         Assert.AreEqual (1, cReadCount, "#2b");
587                         Assert.AreEqual (0, rReadCount, "#3b");
588                 }
589
590                 [Test]
591                 public void RecursiveUpgradePropertiesTest ()
592                 {
593                         var v = new ReaderWriterLockSlim (LockRecursionPolicy.SupportsRecursion);
594
595                         v.EnterUpgradeableReadLock ();
596                         v.EnterUpgradeableReadLock ();
597
598                         Assert.AreEqual (true, v.IsUpgradeableReadLockHeld, "#1a");
599                         Assert.AreEqual (false, v.IsReadLockHeld, "#11a");
600                         Assert.AreEqual (0, v.CurrentReadCount, "#2a");
601                         Assert.AreEqual (2, v.RecursiveUpgradeCount, "#3a");
602
603                         bool upLock = false, rLock = false;
604                         int rCount = -1, rUCount = -1;
605
606                         Thread t = new Thread ((_) => {
607                                         upLock = v.IsUpgradeableReadLockHeld;
608                                         rLock = v.IsReadLockHeld;
609                                         rCount = v.CurrentReadCount;
610                                         rUCount = v.RecursiveUpgradeCount;
611                                 });
612
613                         t.Start ();
614                         t.Join ();
615
616                         Assert.AreEqual (false, upLock, "#1b");
617                         Assert.AreEqual (false, rLock, "#11b");
618                         Assert.AreEqual (0, rCount, "#2b");
619                         Assert.AreEqual (0, rUCount, "#3b");
620                 }
621
622                 [Test]
623                 public void RecursiveWritePropertiesTest ()
624                 {
625                         var v = new ReaderWriterLockSlim (LockRecursionPolicy.SupportsRecursion);
626
627                         v.EnterWriteLock ();
628                         v.EnterWriteLock ();
629
630                         Assert.AreEqual (true, v.IsWriteLockHeld, "#1a");
631                         Assert.AreEqual (2, v.RecursiveWriteCount, "#3a");
632
633                         bool wLock = false;
634                         int rWrite = -1;
635
636                         Thread t = new Thread ((_) => {
637                                         wLock = v.IsWriteLockHeld;
638                                         rWrite = v.RecursiveWriteCount;
639                                 });
640
641                         t.Start ();
642                         t.Join ();
643
644                         Assert.AreEqual (false, wLock, "#1b");
645                         Assert.AreEqual (0, rWrite, "#3b");
646                 }
647
648                 [Test]
649                 public void RecursiveEnterExitReadTest ()
650                 {
651                         var v = new ReaderWriterLockSlim (LockRecursionPolicy.SupportsRecursion);
652
653                         v.EnterReadLock ();
654                         v.EnterReadLock ();
655                         v.EnterReadLock ();
656
657                         Assert.IsTrue (v.IsReadLockHeld);
658                         Assert.AreEqual (3, v.RecursiveReadCount);
659
660                         v.ExitReadLock ();
661
662                         Assert.IsTrue (v.IsReadLockHeld);
663                         Assert.AreEqual (2, v.RecursiveReadCount);
664                 }
665
666                 [Test]
667                 public void RecursiveEnterExitWriteTest ()
668                 {
669                         var v = new ReaderWriterLockSlim (LockRecursionPolicy.SupportsRecursion);
670
671                         v.EnterWriteLock ();
672                         v.EnterWriteLock ();
673                         v.EnterWriteLock ();
674
675                         Assert.IsTrue (v.IsWriteLockHeld);
676                         Assert.AreEqual (3, v.RecursiveWriteCount);
677
678                         v.ExitWriteLock ();
679                         v.ExitWriteLock ();
680
681                         Assert.IsTrue (v.IsWriteLockHeld);
682                         Assert.AreEqual (1, v.RecursiveWriteCount);
683                 }
684
685                 [Test]
686                 public void RecursiveEnterExitUpgradableTest ()
687                 {
688                         var v = new ReaderWriterLockSlim (LockRecursionPolicy.SupportsRecursion);
689
690                         v.EnterUpgradeableReadLock ();
691                         v.EnterUpgradeableReadLock ();
692                         v.EnterUpgradeableReadLock ();
693
694                         Assert.IsTrue (v.IsUpgradeableReadLockHeld);
695                         Assert.AreEqual (3, v.RecursiveUpgradeCount);
696
697                         v.ExitUpgradeableReadLock ();
698
699                         Assert.IsTrue (v.IsUpgradeableReadLockHeld);
700                         Assert.AreEqual (2, v.RecursiveUpgradeCount);
701                 }
702
703                 [Test]
704                 public void RecursiveWriteUpgradeReadTest ()
705                 {
706                         var rwlock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
707
708                         rwlock.EnterWriteLock ();
709                         Assert.IsTrue (rwlock.IsWriteLockHeld);
710                         rwlock.EnterUpgradeableReadLock ();
711                         Assert.IsTrue (rwlock.IsUpgradeableReadLockHeld);
712                         rwlock.EnterReadLock ();
713                         Assert.IsTrue (rwlock.IsReadLockHeld);
714                         rwlock.ExitUpgradeableReadLock();
715                         Assert.IsFalse (rwlock.IsUpgradeableReadLockHeld);
716                         Assert.IsTrue (rwlock.IsReadLockHeld);
717                         Assert.IsTrue (rwlock.IsWriteLockHeld);
718
719                         rwlock.ExitReadLock ();
720                         Assert.IsTrue (rwlock.IsWriteLockHeld);
721                 }
722
723                 [Test]
724                 public void RecursiveWriteUpgradeTest ()
725                 {
726                         ReaderWriterLockSlim rwlock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
727
728                         rwlock.EnterWriteLock ();
729                         Assert.IsTrue (rwlock.IsWriteLockHeld);
730                         rwlock.EnterUpgradeableReadLock ();
731                         Assert.IsTrue (rwlock.IsUpgradeableReadLockHeld);
732                         rwlock.ExitUpgradeableReadLock ();
733                         Assert.IsFalse (rwlock.IsUpgradeableReadLockHeld);
734                         Assert.IsTrue (rwlock.IsWriteLockHeld);
735                         rwlock.ExitWriteLock ();
736                         Assert.IsFalse (rwlock.IsWriteLockHeld);
737                         rwlock.EnterWriteLock ();
738                         Assert.IsTrue (rwlock.IsWriteLockHeld);
739                 }
740
741                 [Test]
742                 public void RecursiveWriteReadAcquisitionInterleaving ()
743                 {
744                         var v = new ReaderWriterLockSlim (LockRecursionPolicy.SupportsRecursion);
745
746                         v.EnterWriteLock ();
747                         Assert.IsTrue (v.IsWriteLockHeld, "#1");
748
749                         bool result = true;
750                         var t = new Thread (delegate () {
751                                         result = v.TryEnterReadLock (100);
752                                 });
753                         t.Start ();
754                         t.Join ();
755                         Assert.IsFalse (result, "#2");
756
757                         v.ExitWriteLock ();
758                         t = new Thread (delegate () {
759                                         result = v.TryEnterReadLock (100);
760                                 });
761                         t.Start ();
762                         t.Join ();
763                         Assert.IsTrue (result, "#3");
764                 }
765         }
766 }