(DISTFILES): Comment out a few missing files.
[mono-project.git] / mcs / class / corlib / System.Threading / ReaderWriterLock.cs
blobc80b7826574e3aca859950f0176bf8dc07b520e7
1 //
2 // System.Threading.ReaderWriterLock.cs
3 //
4 // Author:
5 // Dick Porter (dick@ximian.com)
6 // Jackson Harper (jackson@ximian.com)
7 // Lluis Sanchez Gual (lluis@ximian.com)
8 //
9 // (C) Ximian, Inc. http://www.ximian.com
10 // (C) 2004 Novell, Inc (http://www.novell.com)
14 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
16 // Permission is hereby granted, free of charge, to any person obtaining
17 // a copy of this software and associated documentation files (the
18 // "Software"), to deal in the Software without restriction, including
19 // without limitation the rights to use, copy, modify, merge, publish,
20 // distribute, sublicense, and/or sell copies of the Software, and to
21 // permit persons to whom the Software is furnished to do so, subject to
22 // the following conditions:
23 //
24 // The above copyright notice and this permission notice shall be
25 // included in all copies or substantial portions of the Software.
26 //
27 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
31 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
32 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
33 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 using System.Collections;
38 namespace System.Threading
40 public sealed class ReaderWriterLock
42 private int seq_num = 1;
43 private int state = 0;
44 private int readers = 0;
45 private LockQueue writer_queue;
46 private Hashtable reader_locks;
47 private int writer_lock_owner;
48 private int readyWaitingReaders = 0;
50 public ReaderWriterLock()
52 writer_queue = new LockQueue (this);
53 reader_locks = new Hashtable ();
56 public bool IsReaderLockHeld {
57 get {
58 lock (this) return reader_locks.ContainsKey (Thread.CurrentThreadId);
62 public bool IsWriterLockHeld {
63 get {
64 lock (this) return (state < 0 && Thread.CurrentThreadId == writer_lock_owner);
68 public int WriterSeqNum {
69 get {
70 lock (this) return seq_num;
74 public void AcquireReaderLock (int millisecondsTimeout)
76 AcquireReaderLock (millisecondsTimeout, 1);
79 void AcquireReaderLock (int millisecondsTimeout, int initialLockCount)
81 lock (this) {
82 if (HasWriterLock ()) {
83 AcquireWriterLock (millisecondsTimeout, initialLockCount);
84 return;
87 object nlocks = reader_locks [Thread.CurrentThreadId];
88 if (nlocks == null)
90 // Not currently holding a reader lock
91 // Wait if there is a write lock
92 readers++;
93 try {
94 if (state < 0 || !writer_queue.IsEmpty) {
95 if (!Monitor.Wait (this, millisecondsTimeout))
96 throw new ApplicationException ("Timeout expired");
98 readyWaitingReaders--;
100 finally {
101 readers--;
104 reader_locks [Thread.CurrentThreadId] = initialLockCount;
105 state += initialLockCount;
107 else {
108 reader_locks [Thread.CurrentThreadId] = ((int)nlocks) + 1;
109 state++;
114 public void AcquireReaderLock(TimeSpan timeout)
116 int ms = CheckTimeout (timeout);
117 AcquireReaderLock ((int) timeout.TotalMilliseconds, 1);
120 public void AcquireWriterLock (int millisecondsTimeout)
122 AcquireWriterLock (millisecondsTimeout, 1);
125 void AcquireWriterLock (int millisecondsTimeout, int initialLockCount)
127 lock (this) {
128 if (HasWriterLock ()) {
129 state--;
130 return;
133 // wait while there are reader locks or another writer lock, or
134 // other threads waiting for the writer lock
135 if (state != 0 || !writer_queue.IsEmpty || readers > 0) {
136 if (!writer_queue.Wait (millisecondsTimeout))
137 throw new ApplicationException ("Timeout expited");
140 state = -initialLockCount;
141 writer_lock_owner = Thread.CurrentThreadId;
142 seq_num++;
146 public void AcquireWriterLock(TimeSpan timeout) {
147 int ms = CheckTimeout (timeout);
148 AcquireWriterLock (ms, 1);
151 public bool AnyWritersSince(int seqNum) {
152 lock (this) {
153 return (this.seq_num > seqNum);
157 public void DowngradeFromWriterLock(ref LockCookie lockCookie)
159 lock (this) {
160 if (!HasWriterLock())
161 throw new ApplicationException ("The thread does not have the writer lock.");
163 state = lockCookie.ReaderLocks;
164 reader_locks [Thread.CurrentThreadId] = state;
165 if (readers > 0) {
166 readyWaitingReaders = readers;
167 Monitor.PulseAll (this);
170 // MSDN: A thread does not block when downgrading from the writer lock,
171 // even if other threads are waiting for the writer lock
175 public LockCookie ReleaseLock()
177 LockCookie cookie;
178 lock (this) {
179 cookie = GetLockCookie ();
180 if (cookie.WriterLocks != 0)
181 ReleaseWriterLock (cookie.WriterLocks);
182 else if (cookie.ReaderLocks != 0) {
183 ReleaseReaderLock (cookie.ReaderLocks, cookie.ReaderLocks);
186 return cookie;
189 public void ReleaseReaderLock()
191 lock (this) {
192 if (HasWriterLock ()) {
193 ReleaseWriterLock ();
194 return;
196 else if (state > 0) {
197 object read_lock_count = reader_locks [Thread.CurrentThreadId];
198 if (read_lock_count != null) {
199 ReleaseReaderLock ((int)read_lock_count, 1);
200 return;
203 throw new ApplicationException ("The thread does not have any reader or writer locks.");
207 void ReleaseReaderLock (int currentCount, int releaseCount)
209 int new_count = currentCount - releaseCount;
211 if (new_count == 0)
212 reader_locks.Remove (Thread.CurrentThreadId);
213 else
214 reader_locks [Thread.CurrentThreadId] = new_count;
216 state -= releaseCount;
217 if (state == 0 && (readers == 0 || readyWaitingReaders <= 0) && !writer_queue.IsEmpty)
218 writer_queue.Pulse ();
221 public void ReleaseWriterLock()
223 lock (this) {
224 if (!HasWriterLock())
225 throw new ApplicationException ("The thread does not have the writer lock.");
227 ReleaseWriterLock (1);
231 void ReleaseWriterLock (int releaseCount)
233 state += releaseCount;
234 if (state == 0) {
235 if (readers > 0) {
236 readyWaitingReaders = readers;
237 Monitor.PulseAll (this);
239 else if (!writer_queue.IsEmpty)
240 writer_queue.Pulse ();
244 public void RestoreLock(ref LockCookie lockCookie)
246 lock (this) {
247 if (lockCookie.WriterLocks != 0)
248 AcquireWriterLock (-1, lockCookie.WriterLocks);
249 else if (lockCookie.ReaderLocks != 0)
250 AcquireReaderLock (-1, lockCookie.ReaderLocks);
254 public LockCookie UpgradeToWriterLock(int millisecondsTimeout)
256 LockCookie cookie;
257 lock (this) {
258 cookie = GetLockCookie ();
259 if (cookie.WriterLocks != 0) {
260 state--;
261 return cookie;
264 if (cookie.ReaderLocks != 0)
265 ReleaseReaderLock (cookie.ReaderLocks, cookie.ReaderLocks);
268 // Don't do this inside the lock, since it can cause a deadlock.
269 AcquireWriterLock (millisecondsTimeout);
270 return cookie;
273 public LockCookie UpgradeToWriterLock(TimeSpan timeout)
275 int ms = CheckTimeout (timeout);
276 return UpgradeToWriterLock (ms);
279 LockCookie GetLockCookie ()
281 LockCookie cookie = new LockCookie (Thread.CurrentThreadId);
283 if (HasWriterLock())
284 cookie.WriterLocks = -state;
285 else {
286 object locks = reader_locks [Thread.CurrentThreadId];
287 if (locks != null) cookie.ReaderLocks = (int)locks;
289 return cookie;
292 bool HasWriterLock ()
294 return (state < 0 && Thread.CurrentThreadId == writer_lock_owner);
297 private int CheckTimeout (TimeSpan timeout)
299 int ms = (int) timeout.TotalMilliseconds;
301 if (ms < -1)
302 throw new ArgumentOutOfRangeException ("timeout",
303 "Number must be either non-negative or -1");
304 return ms;