diff options
author | Jérémie Laval <jeremie.laval@gmail.com> | 2011-01-11 16:39:29 +0300 |
---|---|---|
committer | Jérémie Laval <jeremie.laval@gmail.com> | 2011-01-13 18:38:43 +0300 |
commit | 2b17a5fa81fd2461814440d1995d2d5633f89036 (patch) | |
tree | 54a38f42ebaac283f0c7587dc547d81b6e317cf3 /mcs/class/Mono.Parallel | |
parent | 8ff4c9d48797523fd88357a86e4953fff74cca13 (diff) |
Protect RwlSlimmer and add Try equivalent
Diffstat (limited to 'mcs/class/Mono.Parallel')
-rw-r--r-- | mcs/class/Mono.Parallel/Mono.Threading/ReaderWriterLockSlimmer.cs | 96 |
1 files changed, 77 insertions, 19 deletions
diff --git a/mcs/class/Mono.Parallel/Mono.Threading/ReaderWriterLockSlimmer.cs b/mcs/class/Mono.Parallel/Mono.Threading/ReaderWriterLockSlimmer.cs index edd1183ebf2..7a84d52cb98 100644 --- a/mcs/class/Mono.Parallel/Mono.Threading/ReaderWriterLockSlimmer.cs +++ b/mcs/class/Mono.Parallel/Mono.Threading/ReaderWriterLockSlimmer.cs @@ -37,18 +37,42 @@ namespace Mono.Threading int rwlock; - public void EnterReadLock () + public void EnterReadLock (ref bool taken) { + if (taken) + throw new ArgumentException ("taken", "taken needs to be set to false"); + SpinWait sw = new SpinWait (); + bool cont = true; + do { while ((rwlock & (RwWrite | RwWait)) > 0) sw.SpinOnce (); - if ((Interlocked.Add (ref rwlock, RwRead) & (RwWait | RwWait)) == 0) - return; + try {} + finally { + if ((Interlocked.Add (ref rwlock, RwRead) & (RwWait | RwWait)) == 0) { + taken = true; + cont = false; + } else { + Interlocked.Add (ref rwlock, -RwRead); + } + } + } while (cont); + } + + public void TryEnterReadLock (ref bool taken) + { + if (taken) + throw new ArgumentException ("taken", "taken needs to be set to false"); - Interlocked.Add (ref rwlock, -RwRead); - } while (true); + try {} + finally { + if ((Interlocked.Add (ref rwlock, RwRead) & (RwWait | RwWrite)) == 0) + taken = true; + else + Interlocked.Add (ref rwlock, -RwRead); + } } public void ExitReadLock () @@ -56,23 +80,57 @@ namespace Mono.Threading Interlocked.Add (ref rwlock, -RwRead); } - public void EnterWriteLock () + public void EnterWriteLock (ref bool taken) { + if (taken) + throw new ArgumentException ("taken", "taken needs to be set to false"); + SpinWait sw = new SpinWait (); - do { - int state = rwlock; - if (state < RwWrite) { - if (Interlocked.CompareExchange (ref rwlock, RwWrite, state) == state) - return; - state = rwlock; - } - // We register our interest in taking the Write lock (if upgradeable it's already done) - while ((state & RwWait) == 0 && Interlocked.CompareExchange (ref rwlock, state | RwWait, state) != state) + int state = rwlock; + + try { + do { state = rwlock; - // Before falling to sleep - while (rwlock > RwWait) - sw.SpinOnce (); - } while (true); + if (state < RwWrite) { + try {} + finally { + if (Interlocked.CompareExchange (ref rwlock, RwWrite, state) == state) + taken = true; + } + if (taken) + return; + + state = rwlock; + } + + while ((state & RwWait) == 0 && Interlocked.CompareExchange (ref rwlock, state | RwWait, state) != state) + state = rwlock; + + while (rwlock > RwWait) + sw.SpinOnce (); + } while (true); + } finally { + state = rwlock; + if (!taken && (state & RwWait) != 0) + Interlocked.CompareExchange (ref rwlock, state - RwWait, state); + } + } + + public void TryEnterWriteLock (ref bool taken) + { + if (taken) + throw new ArgumentException ("taken", "taken needs to be set to false"); + + int state = rwlock; + + if (state >= RwWrite) + return; + + try {} + finally { + if (Interlocked.CompareExchange (ref rwlock, RwWrite, state) == state) + taken = true; + } } public void ExitWriteLock () |