[corlib] CoreRT System.Threading.Tasks (#6672)
[mono-project.git] / mcs / class / System.ComponentModel.Composition.4.5 / src / ComponentModel / System / ComponentModel / Composition / Hosting / CompositionLock.cs
blob55a5007e3ef43283380dc9b9820c48a215ffb8e4
1 // -----------------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation. All rights reserved.
3 // -----------------------------------------------------------------------
4 #define SINGLETHREADEDLOCKENFORCEMENT
5 using System;
6 using System.Collections.Generic;
7 using System.ComponentModel.Composition.Primitives;
8 using System.Diagnostics;
9 using System.Linq;
10 using System.Runtime.CompilerServices;
11 using Microsoft.Internal;
12 using Microsoft.Internal.Collections;
13 using System.Threading;
14 using Lock = Microsoft.Internal.Lock;
16 namespace System.ComponentModel.Composition.Hosting
18 // This a a lock class that needs to be held in order to perform any mutation of the parts/parts state in the composition
19 // Today's implementation relies on the AppDomain-wide re-entrant lock for changes on the composition, and a narrow lock for changes in
20 // the state of the specific ImportEngine
21 // Today we make several assumptions to ensure thread-safety:
22 // 1. Each composition doesn't change lock affinity
23 // 2. Every part of the system that updates the status of the parts (in our case ImportEngine) needs to hold the same wide - lock
24 // 3. State of the import engine that gets accessed outside of the wide lock needs to be accessed in the context of the narrow lock
25 // 4. Narrow lock CAN be taken inside the wide lock
26 // 5. Wide lock CANNOT be taken inside the narrow lock
27 // 6. No 3rd party code will EVER get called inside the narrow lock
28 // Sadly, this means that we WILL be calling 3rd party code under a lock, but as long as the lock is re-entrant and they can't invoke us on anotehr thread
29 // we have no issue, other than potential overlocking
30 internal sealed class CompositionLock : IDisposable
32 // narrow lock
33 private readonly Lock _stateLock = null;
34 // wide lock
35 private static object _compositionLock = new object();
37 private int _isDisposed = 0;
38 private bool _isThreadSafe = false;
40 private static readonly EmptyLockHolder _EmptyLockHolder = new EmptyLockHolder();
42 public CompositionLock(bool isThreadSafe)
44 this._isThreadSafe = isThreadSafe;
45 if (isThreadSafe)
47 this._stateLock = new Lock();
51 public void Dispose()
53 if (this._isThreadSafe)
55 if (Interlocked.CompareExchange(ref this._isDisposed, 1, 0) == 0)
57 this._stateLock.Dispose();
62 public bool IsThreadSafe
64 get
66 return this._isThreadSafe;
70 private void EnterCompositionLock()
72 #pragma warning disable 618
73 if (this._isThreadSafe)
75 Monitor.Enter(_compositionLock);
77 #pragma warning restore 618
80 private void ExitCompositionLock()
82 if (this._isThreadSafe)
84 Monitor.Exit(_compositionLock);
88 public IDisposable LockComposition()
90 if (this._isThreadSafe)
92 return new CompositionLockHolder(this);
94 else
96 return _EmptyLockHolder;
100 public IDisposable LockStateForRead()
102 if (this._isThreadSafe)
104 return new ReadLock(this._stateLock);
106 else
108 return _EmptyLockHolder;
112 public IDisposable LockStateForWrite()
114 if (this._isThreadSafe)
116 return new WriteLock(this._stateLock);
118 else
120 return _EmptyLockHolder;
124 // NOTE : this should NOT be changed to a struct as ImportEngine relies on it
125 public sealed class CompositionLockHolder : IDisposable
127 private CompositionLock _lock;
128 private int _isDisposed;
130 public CompositionLockHolder(CompositionLock @lock)
132 this._lock = @lock;
134 this._isDisposed = 0;
135 this._lock.EnterCompositionLock();
138 public void Dispose()
140 if (Interlocked.CompareExchange(ref this._isDisposed, 1, 0) == 0)
142 this._lock.ExitCompositionLock();
147 private sealed class EmptyLockHolder : IDisposable
149 public void Dispose()