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