1
// -----------------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation. All rights reserved.
3 // -----------------------------------------------------------------------
4 #define SINGLETHREADEDLOCKENFORCEMENT
6 using System
.Collections
.Generic
;
7 using System
.ComponentModel
.Composition
.Primitives
;
8 using System
.Diagnostics
;
10 using System
.Runtime
.CompilerServices
;
11 using Microsoft
.Internal
;
12 using Microsoft
.Internal
.Collections
;
13 using System
.Threading
;
15 namespace System
.ComponentModel
.Composition
.Hosting
17 // This a a lock class that needs to be held in order to perform any mutation of the parts/parts state in the composition
18 // Today's implementation relies on the AppDomain-wide re-entrant lock for changes on the composition, and a narrow lock for changes in
19 // the state of the specific ImportEngine
20 // Today we make several assumptions to ensure thread-safety:
21 // 1. Each composition doesn't change lock affinity
22 // 2. Every part of the system that updates the status of the parts (in our case ImportEngine) needs to hold the same wide - lock
23 // 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
24 // 4. Narrow lock CAN be taken inside the wide lock
25 // 5. Wide lock CANNOT be taken inside the narrow lock
26 // 6. No 3rd party code will EVER get called inside the narrow lock
27 // 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
28 // we have no issue, other than potential overlocking
29 internal sealed class CompositionLock
: IDisposable
32 private readonly Lock _stateLock
= null;
34 private static object _compositionLock
= new object();
36 private int _isDisposed
= 0;
37 private bool _isThreadSafe
= false;
39 private static readonly EmptyLockHolder _EmptyLockHolder
= new EmptyLockHolder();
41 public CompositionLock(bool isThreadSafe
)
43 this._isThreadSafe
= isThreadSafe
;
46 this._stateLock
= new Lock();
52 if (this._isThreadSafe
)
54 if (Interlocked
.CompareExchange(ref this._isDisposed
, 1, 0) == 0)
56 this._stateLock
.Dispose();
61 public bool IsThreadSafe
65 return this._isThreadSafe
;
69 private void EnterCompositionLock()
71 #pragma warning disable 618
72 if (this._isThreadSafe
)
74 Monitor
.Enter(_compositionLock
);
76 #pragma warning restore 618
79 private void ExitCompositionLock()
81 if (this._isThreadSafe
)
83 Monitor
.Exit(_compositionLock
);
87 public IDisposable
LockComposition()
89 if (this._isThreadSafe
)
91 return new CompositionLockHolder(this);
95 return _EmptyLockHolder
;
99 public IDisposable
LockStateForRead()
101 if (this._isThreadSafe
)
103 return new ReadLock(this._stateLock
);
107 return _EmptyLockHolder
;
111 public IDisposable
LockStateForWrite()
113 if (this._isThreadSafe
)
115 return new WriteLock(this._stateLock
);
119 return _EmptyLockHolder
;
123 // NOTE : this should NOT be changed to a struct as ImportEngine relies on it
124 public sealed class CompositionLockHolder
: IDisposable
126 private CompositionLock _lock
;
127 private int _isDisposed
;
129 public CompositionLockHolder(CompositionLock
@lock)
133 this._isDisposed
= 0;
134 this._lock
.EnterCompositionLock();
137 public void Dispose()
139 if (Interlocked
.CompareExchange(ref this._isDisposed
, 1, 0) == 0)
141 this._lock
.ExitCompositionLock();
146 private sealed class EmptyLockHolder
: IDisposable
148 public void Dispose()