update MEF to preview 9
[mcs.git] / class / System.ComponentModel.Composition / src / ComponentModel / System / ComponentModel / Composition / Hosting / CompositionLock.cs
blobb3dd0ea062f7578fb4a57f5fbf5c45e442fae27b
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;
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
31 // narrow lock
32 private readonly Lock _stateLock = null;
33 // wide lock
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;
44 if (isThreadSafe)
46 this._stateLock = new Lock();
50 public void Dispose()
52 if (this._isThreadSafe)
54 if (Interlocked.CompareExchange(ref this._isDisposed, 1, 0) == 0)
56 this._stateLock.Dispose();
61 public bool IsThreadSafe
63 get
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);
93 else
95 return _EmptyLockHolder;
99 public IDisposable LockStateForRead()
101 if (this._isThreadSafe)
103 return new ReadLock(this._stateLock);
105 else
107 return _EmptyLockHolder;
111 public IDisposable LockStateForWrite()
113 if (this._isThreadSafe)
115 return new WriteLock(this._stateLock);
117 else
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)
131 this._lock = @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()