1 //
2 // ReaderWriterLockTest.cs - NUnit Test Cases for System.Threading.ReaderWriterLock
3 //
4 // Author:
5 //   Lluis Sanchez Gual (lluis@ximian.com)
6 //
7 // (C) 2004 Novell, Inc (http://www.novell.com)
8 //
9 
10 using NUnit.Framework;
11 using System;
12 using System.Threading;
13 
14 namespace MonoTests.System.Threading
15 {
16 	[TestFixture]
17 	public class ReaderWriterLockTest
18 	{
19 		ReaderWriterLock rwlock;
20 
21 		class ThreadRunner
22 		{
23 			public ThreadStart SecondaryThread;
24 			public Exception ResultException;
25 			public Thread RunningThread;
26 
Run()27 			public void Run ()
28 			{
29 				try
30 				{
31 					SecondaryThread();
32 				}
33 				catch (Exception ex)
34 				{
35 					ResultException = ex;
36 				}
37 			}
38 
Join()39 			public void Join ()
40 			{
41 				RunningThread.Join (5000);
42 				if (ResultException != null) throw ResultException;
43 			}
44 		}
45 
RunThread(ThreadStart ts)46 		void RunThread (ThreadStart ts)
47 		{
48 			ThreadRunner tr = StartThread (ts);
49 			tr.Join ();
50 		}
51 
StartThread(ThreadStart ts)52 		ThreadRunner StartThread (ThreadStart ts)
53 		{
54 			ThreadRunner tr = new ThreadRunner();
55 			tr.SecondaryThread = ts;
56 			Thread t = new Thread (new ThreadStart (tr.Run));
57 			tr.RunningThread = t;
58 			t.Start ();
59 			return tr;
60 		}
61 
62 		[Test]
TestIsReaderLockHeld()63 		public void TestIsReaderLockHeld ()
64 		{
65 			rwlock = new ReaderWriterLock ();
66 			Assert.IsTrue (!rwlock.IsReaderLockHeld, "#1");
67 			rwlock.AcquireReaderLock (500);
68 			Assert.IsTrue (rwlock.IsReaderLockHeld, "#1");
69 			RunThread (new ThreadStart (IsReaderLockHeld_2));
70 			rwlock.ReleaseReaderLock ();
71 		}
72 
IsReaderLockHeld_2()73 		private void IsReaderLockHeld_2 ()
74 		{
75 			Assert.IsTrue (!rwlock.IsReaderLockHeld);
76 		}
77 
78 		[Test]
TestIsWriterLockHeld()79 		public void TestIsWriterLockHeld ()
80 		{
81 			rwlock = new ReaderWriterLock ();
82 			Assert.IsTrue (!rwlock.IsWriterLockHeld, "#1");
83 			rwlock.AcquireWriterLock (500);
84 			Assert.IsTrue (rwlock.IsWriterLockHeld, "#2");
85 			RunThread (new ThreadStart (IsWriterLockHeld_2));
86 			rwlock.ReleaseWriterLock ();
87 		}
88 
IsWriterLockHeld_2()89 		private void IsWriterLockHeld_2 ()
90 		{
91 			Assert.IsTrue (!rwlock.IsWriterLockHeld);
92 		}
93 
94 		[Test]
TestAcquireLocks()95 		public void TestAcquireLocks ()
96 		{
97 			rwlock = new ReaderWriterLock ();
98 			rwlock.AcquireReaderLock (500);
99 			rwlock.AcquireReaderLock (500);
100 			rwlock.ReleaseReaderLock ();
101 				Assert.IsTrue (rwlock.IsReaderLockHeld, "#1");
102 			RunThread (new ThreadStart (AcquireLock_readerWorks));
103 			Assert.IsTrue (rwlock.IsReaderLockHeld);
104 
105 			RunThread (new ThreadStart (AcquireLock_writerFails));
106 			rwlock.ReleaseReaderLock ();
107 			Assert.IsTrue (!rwlock.IsReaderLockHeld);
108 
109 			RunThread (new ThreadStart (AcquireLock_writerWorks));
110 
111 			rwlock.AcquireWriterLock (200);
112 			RunThread (new ThreadStart (AcquireLock_writerFails));
113 			RunThread (new ThreadStart (AcquireLock_readerFails));
114 			rwlock.ReleaseWriterLock ();
115 		}
116 
AcquireLock_readerWorks()117 		void AcquireLock_readerWorks ()
118 		{
119 			rwlock.AcquireReaderLock (200);
120 			rwlock.AcquireReaderLock (200);
121 			rwlock.ReleaseReaderLock ();
122 			Assert.IsTrue (rwlock.IsReaderLockHeld);
123 			rwlock.ReleaseReaderLock ();
124 			Assert.IsTrue (!rwlock.IsReaderLockHeld);
125 		}
126 
AcquireLock_writerFails()127 		void AcquireLock_writerFails ()
128 		{
129 			try
130 			{
131 				rwlock.AcquireWriterLock (200);
132 				rwlock.ReleaseWriterLock ();
133 				throw new Exception ("Should not get writer lock");
134 			}
135 			catch (Exception)
136 			{
137 			}
138 		}
139 
AcquireLock_writerWorks()140 		void AcquireLock_writerWorks ()
141 		{
142 			rwlock.AcquireWriterLock (200);
143 			rwlock.ReleaseWriterLock ();
144 		}
145 
AcquireLock_readerFails()146 		void AcquireLock_readerFails ()
147 		{
148 			try
149 			{
150 				rwlock.AcquireReaderLock (200);
151 				rwlock.ReleaseReaderLock ();
152 				throw new Exception ("Should not get reader lock");
153 			}
154 			catch (Exception)
155 			{
156 			}
157 		}
158 
159 		[Test]
TestReleaseRestoreReaderLock()160 		public void TestReleaseRestoreReaderLock ()
161 		{
162 			rwlock = new ReaderWriterLock ();
163 			rwlock.AcquireReaderLock (500);
164 			rwlock.AcquireReaderLock (500);
165 			Assert.IsTrue (rwlock.IsReaderLockHeld);
166 
167 			LockCookie co = rwlock.ReleaseLock ();
168 			RunThread (new ThreadStart (AcquireLock_writerWorks));
169 
170 			rwlock.RestoreLock (ref co);
171 			RunThread (new ThreadStart (AcquireLock_writerFails));
172 
173 			rwlock.ReleaseReaderLock ();
174 			Assert.IsTrue (rwlock.IsReaderLockHeld);
175 			rwlock.ReleaseReaderLock ();
176 			Assert.IsTrue (!rwlock.IsReaderLockHeld);
177 		}
178 
179 		[Test]
TestReleaseRestoreWriterLock()180 		public void TestReleaseRestoreWriterLock ()
181 		{
182 			rwlock = new ReaderWriterLock ();
183 			rwlock.AcquireWriterLock (500);
184 			rwlock.AcquireWriterLock (500);
185 			Assert.IsTrue (rwlock.IsWriterLockHeld);
186 
187 			LockCookie co = rwlock.ReleaseLock ();
188 			RunThread (new ThreadStart (AcquireLock_readerWorks));
189 
190 			rwlock.RestoreLock (ref co);
191 			RunThread (new ThreadStart (AcquireLock_readerFails));
192 
193 			rwlock.ReleaseWriterLock ();
194 			Assert.IsTrue (rwlock.IsWriterLockHeld);
195 			rwlock.ReleaseWriterLock ();
196 			Assert.IsTrue (!rwlock.IsWriterLockHeld);
197 		}
198 
199 		[Test]
TestUpgradeDowngradeLock()200 		public void TestUpgradeDowngradeLock ()
201 		{
202 			rwlock = new ReaderWriterLock ();
203 			rwlock.AcquireReaderLock (200);
204 			rwlock.AcquireReaderLock (200);
205 
206 			LockCookie co = rwlock.UpgradeToWriterLock (200);
207 			Assert.IsTrue (!rwlock.IsReaderLockHeld);
208 			Assert.IsTrue (rwlock.IsWriterLockHeld);
209 			RunThread (new ThreadStart (AcquireLock_writerFails));
210 
211 			rwlock.DowngradeFromWriterLock (ref co);
212 			Assert.IsTrue (rwlock.IsReaderLockHeld);
213 			Assert.IsTrue (!rwlock.IsWriterLockHeld);
214 			RunThread (new ThreadStart (AcquireLock_readerWorks));
215 
216 			rwlock.ReleaseReaderLock ();
217 			Assert.IsTrue (rwlock.IsReaderLockHeld);
218 			rwlock.ReleaseReaderLock ();
219 			Assert.IsTrue (!rwlock.IsReaderLockHeld);
220 		}
221 
222 		[Test]
TestReaderInsideWriter()223 		public void TestReaderInsideWriter ()
224 		{
225 			// Reader acquires and releases work like the writer equivalent
226 
227 			rwlock = new ReaderWriterLock ();
228 			rwlock.AcquireWriterLock (-1);
229 			rwlock.AcquireReaderLock (-1);
230 			Assert.IsTrue (!rwlock.IsReaderLockHeld);
231 			Assert.IsTrue (rwlock.IsWriterLockHeld);
232 			rwlock.AcquireReaderLock (-1);
233 			Assert.IsTrue (!rwlock.IsReaderLockHeld);
234 			Assert.IsTrue (rwlock.IsWriterLockHeld);
235 			rwlock.ReleaseWriterLock ();
236 			Assert.IsTrue (!rwlock.IsReaderLockHeld);
237 			Assert.IsTrue (rwlock.IsWriterLockHeld);
238 			rwlock.ReleaseReaderLock ();
239 			Assert.IsTrue (!rwlock.IsReaderLockHeld);
240 			Assert.IsTrue (rwlock.IsWriterLockHeld);
241 			rwlock.ReleaseReaderLock ();
242 			Assert.IsTrue (!rwlock.IsReaderLockHeld);
243 			Assert.IsTrue (!rwlock.IsWriterLockHeld);
244 		}
245 
246 		[Test]
TestReaderMustWaitWriter()247 		public void TestReaderMustWaitWriter ()
248 		{
249 			// A thread cannot get the reader lock if there are other threads
250 			// waiting for the writer lock.
251 
252 			rwlock = new ReaderWriterLock ();
253 			rwlock.AcquireWriterLock (200);
254 
255 			ThreadRunner tr = StartThread (new ThreadStart (ReaderMustWaitWriter_2));
256 			Thread.Sleep (200);
257 
258 			RunThread (new ThreadStart (AcquireLock_readerFails));
259 
260 			rwlock.ReleaseReaderLock ();
261 			tr.Join ();
262 		}
263 
ReaderMustWaitWriter_2()264 		void ReaderMustWaitWriter_2 ()
265 		{
266 			rwlock.AcquireWriterLock (2000);
267 			rwlock.ReleaseWriterLock ();
268 		}
269 
270 		[Test]
TestBug_55911()271 		public void TestBug_55911 ()
272 		{
273 			rwlock = new ReaderWriterLock ();
274 
275 			rwlock.AcquireReaderLock (Timeout.Infinite);
276 			try {
277 				LockCookie lc = rwlock.UpgradeToWriterLock (Timeout.Infinite);
278 			}
279 			finally { rwlock.ReleaseReaderLock(); }
280 
281 			rwlock.AcquireReaderLock (Timeout.Infinite);
282 			try {
283 				LockCookie lc = rwlock.UpgradeToWriterLock (Timeout.Infinite);
284 			}
285 			finally { rwlock.ReleaseReaderLock(); }
286 		}
287 
288 		[Test]
TestBug_55909()289 		public void TestBug_55909 ()
290 		{
291 			rwlock = new ReaderWriterLock ();
292 			ThreadRunner tr = StartThread (new ThreadStart(Bug_55909_Thread2));
293 			Thread.Sleep (200);
294 			rwlock.AcquireReaderLock (Timeout.Infinite);
295 			try {
296 				LockCookie lc = rwlock.UpgradeToWriterLock (Timeout.Infinite);
297 				Thread.Sleep (500);
298 			}
299 			finally { rwlock.ReleaseReaderLock(); }
300 
301 			tr.Join ();
302 		}
303 
Bug_55909_Thread2()304 		public void Bug_55909_Thread2 ()
305 		{
306 			rwlock.AcquireReaderLock(Timeout.Infinite);
307 			try {
308 				Thread.Sleep (1000);
309 				LockCookie lc = rwlock.UpgradeToWriterLock (Timeout.Infinite);
310 				Thread.Sleep (500);
311 			}
312 			finally { rwlock.ReleaseReaderLock(); }
313 		}
314 
315 		[Test]
TestBug_55909_bis()316 		public void TestBug_55909_bis ()
317 		{
318 			rwlock = new ReaderWriterLock ();
319 			ThreadRunner tr1 = StartThread (new ThreadStart(Bug_55909_bis_ReaderWriter));
320 			Thread.Sleep(100);
321 			ThreadRunner tr2 = StartThread (new ThreadStart(Bug_55909_bis_Reader));
322 			Thread.Sleep(100);
323 			ThreadRunner tr3 = StartThread (new ThreadStart(Bug_55909_bis_Writer));
324 			Thread.Sleep(100);
325 			ThreadRunner tr4 = StartThread (new ThreadStart(Bug_55909_bis_Reader));
326 			tr1.Join ();
327 			tr2.Join ();
328 			tr3.Join ();
329 			tr4.Join ();
330 		}
331 
Bug_55909_bis_Reader()332 		void Bug_55909_bis_Reader ()
333 		{
334 			rwlock.AcquireReaderLock(-1);
335 			Thread.Sleep(2000);
336 			rwlock.ReleaseReaderLock();
337 		}
338 
Bug_55909_bis_ReaderWriter()339 		void Bug_55909_bis_ReaderWriter ()
340 		{
341 			rwlock.AcquireReaderLock(-1);
342 			LockCookie lc = rwlock.UpgradeToWriterLock(-1);
343 			Thread.Sleep(1000);
344 			rwlock.DowngradeFromWriterLock(ref lc);
345 			rwlock.ReleaseReaderLock();
346 		}
347 
Bug_55909_bis_Writer()348 		void Bug_55909_bis_Writer ()
349 		{
350 			rwlock.AcquireWriterLock(-1);
351 			rwlock.ReleaseWriterLock();
352 		}
353 
354 
355 		[Test]
TestBug_475124()356 		public void TestBug_475124 ()
357 		{
358 			LockCookie lc1, lc2;
359 
360 			rwlock = new ReaderWriterLock ();
361 
362 			Assert.IsFalse (rwlock.IsReaderLockHeld, "A1");
363 			Assert.IsFalse (rwlock.IsWriterLockHeld, "A2");
364 
365 			rwlock.AcquireReaderLock (Timeout.Infinite);
366 
367 			Assert.IsTrue (rwlock.IsReaderLockHeld, "B1");
368 			Assert.IsFalse (rwlock.IsWriterLockHeld, "B2");
369 
370 			lc1 = rwlock.UpgradeToWriterLock (Timeout.Infinite);
371 
372 			Assert.IsFalse (rwlock.IsReaderLockHeld, "C1");
373 			Assert.IsTrue (rwlock.IsWriterLockHeld, "C2");
374 
375 			rwlock.AcquireReaderLock (Timeout.Infinite);
376 
377 			Assert.IsFalse (rwlock.IsReaderLockHeld, "D1");
378 			Assert.IsTrue (rwlock.IsWriterLockHeld, "D2");
379 
380 			lc2 = rwlock.UpgradeToWriterLock (Timeout.Infinite);
381 
382 			Assert.IsFalse (rwlock.IsReaderLockHeld, "E1");
383 			Assert.IsTrue (rwlock.IsWriterLockHeld, "E2");
384 
385 			rwlock.DowngradeFromWriterLock (ref lc2);
386 
387 			Assert.IsFalse (rwlock.IsReaderLockHeld, "F1");
388 			Assert.IsTrue (rwlock.IsWriterLockHeld, "F2");
389 
390 			rwlock.ReleaseReaderLock ();
391 
392 			Assert.IsFalse (rwlock.IsReaderLockHeld, "G1");
393 			Assert.IsTrue (rwlock.IsWriterLockHeld, "G2");
394 
395 			rwlock.DowngradeFromWriterLock (ref lc1);
396 
397 			Assert.IsTrue (rwlock.IsReaderLockHeld, "H1");
398 			Assert.IsFalse (rwlock.IsWriterLockHeld, "H2");
399 
400 			rwlock.ReleaseReaderLock ();
401 
402 			Assert.IsFalse (rwlock.IsReaderLockHeld, "I1");
403 			Assert.IsFalse (rwlock.IsWriterLockHeld, "I2");
404 		}
405 
406 		// this tests how downgrade works when multiple writer locks
407 		// are acquired - as long as the LockCookie referes to an
408 		// upgrade where there was already a writer lock, downgrade
409 		// behaves like a non-blocking ReleaseWriterLock
410 		[Test]
DowngradeTest()411 		public void DowngradeTest ()
412 		{
413 			LockCookie lc1, lc2, lc3, lc4;
414 
415 			rwlock = new ReaderWriterLock ();
416 
417 			rwlock.AcquireReaderLock (Timeout.Infinite);
418 			lc1 = rwlock.UpgradeToWriterLock (Timeout.Infinite);
419 			rwlock.AcquireReaderLock (Timeout.Infinite);
420 			lc2 = rwlock.UpgradeToWriterLock (Timeout.Infinite);
421 			rwlock.AcquireReaderLock (Timeout.Infinite);
422 			lc3 = rwlock.UpgradeToWriterLock (Timeout.Infinite);
423 			rwlock.AcquireReaderLock (Timeout.Infinite);
424 			lc4 = rwlock.UpgradeToWriterLock (Timeout.Infinite);
425 
426 			rwlock.DowngradeFromWriterLock (ref lc2);
427 
428 			Assert.IsFalse (rwlock.IsReaderLockHeld, "A1");
429 			Assert.IsTrue (rwlock.IsWriterLockHeld, "A2");
430 
431 			rwlock.ReleaseReaderLock ();
432 
433 			Assert.IsFalse (rwlock.IsReaderLockHeld, "B1");
434 			Assert.IsTrue (rwlock.IsWriterLockHeld, "B2");
435 
436 			rwlock.DowngradeFromWriterLock (ref lc4);
437 
438 			Assert.IsFalse (rwlock.IsReaderLockHeld, "C1");
439 			Assert.IsTrue (rwlock.IsWriterLockHeld, "C2");
440 
441 			rwlock.ReleaseReaderLock ();
442 
443 			Assert.IsFalse (rwlock.IsReaderLockHeld, "D1");
444 			Assert.IsTrue (rwlock.IsWriterLockHeld, "D2");
445 
446 			rwlock.DowngradeFromWriterLock (ref lc3);
447 
448 			Assert.IsFalse (rwlock.IsReaderLockHeld, "E1");
449 			Assert.IsTrue (rwlock.IsWriterLockHeld, "E2");
450 
451 			rwlock.ReleaseReaderLock ();
452 
453 			Assert.IsFalse (rwlock.IsReaderLockHeld, "F1");
454 			Assert.IsTrue (rwlock.IsWriterLockHeld, "F2");
455 
456 			rwlock.DowngradeFromWriterLock (ref lc1);
457 
458 			Assert.IsTrue (rwlock.IsReaderLockHeld, "G1");
459 			Assert.IsFalse (rwlock.IsWriterLockHeld, "G2");
460 
461 			rwlock.ReleaseReaderLock ();
462 
463 			Assert.IsFalse (rwlock.IsReaderLockHeld, "H1");
464 			Assert.IsFalse (rwlock.IsWriterLockHeld, "H2");
465 		}
466 	}
467 }
468