Merge pull request #3240 from alexanderkyte/aot_compiler_leaks
[mono.git] / mcs / class / corlib / System.Runtime.Remoting.Contexts / SynchronizationAttribute.cs
1 //
2 // System.Runtime.Remoting.Contexts.SynchronizationAttribute.cs
3 //
4 // Author:
5 //   Lluis Sanchez Gual (lluis@ximian.com)
6 //
7 // (C) Novell, Inc.  http://www.ximian.com
8 // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
17 // 
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 // 
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 //
29
30 using System.Threading;
31 using System.Runtime.Remoting.Messaging;
32 using System.Runtime.Remoting.Activation;
33
34 namespace System.Runtime.Remoting.Contexts
35 {
36         [AttributeUsage(AttributeTargets.Class)]
37         [Serializable]
38         [System.Runtime.InteropServices.ComVisible (true)]
39         public class SynchronizationAttribute: ContextAttribute, IContributeClientContextSink, IContributeServerContextSink
40         {
41                 public const int NOT_SUPPORTED = 1;
42                 public const int SUPPORTED = 2;
43                 public const int REQUIRED = 4;
44                 public const int REQUIRES_NEW = 8;
45                 
46                 bool _bReEntrant;
47                 int _flavor;
48
49                 [NonSerialized]
50                 int _lockCount;
51                 
52                 [NonSerialized]
53                 Mutex _mutex = new Mutex (false);
54                 [NonSerialized]
55                 Thread _ownerThread;
56                 
57                 public SynchronizationAttribute ()
58                 : this (REQUIRES_NEW, false)
59                 {
60                 }
61                 
62                 public SynchronizationAttribute (bool reEntrant)
63                 : this (REQUIRES_NEW, reEntrant)
64                 {
65                 }
66                 
67                 public SynchronizationAttribute (int flag)
68                 : this (flag, false)
69                 {
70                 }
71                 
72                 public SynchronizationAttribute (int flag, bool reEntrant)
73                 : base ("Synchronization")
74                 {
75                         if (flag != NOT_SUPPORTED && flag != REQUIRED && flag != REQUIRES_NEW && flag != SUPPORTED)
76                                 throw new ArgumentException ("flag");
77                                 
78                         _bReEntrant = reEntrant;
79                         _flavor = flag;
80                 }
81                 
82                 public virtual bool IsReEntrant
83                 {
84                         get { return _bReEntrant; }
85                 }
86                 
87                 public virtual bool Locked
88                 {
89                         get 
90                         { 
91                                 return _lockCount > 0; 
92                         }
93                         
94                         set 
95                         {
96                                 if (value)
97                                 {
98                                         AcquireLock ();
99                                         lock (this)
100                                         {
101                                                 if (_lockCount > 1)
102                                                         ReleaseLock (); // Thread already had the lock
103                                         }
104                                 }
105                                 else
106                                 {
107                                         lock (this)
108                                         {
109                                                 while (_lockCount > 0 && _ownerThread == Thread.CurrentThread) {
110                                                         ReleaseLock ();
111                                                 }
112                                         }
113                                 }
114                         }
115                 }
116                 
117                 internal void AcquireLock ()
118                 {
119                         _mutex.WaitOne ();
120                         
121                         lock (this)
122                         {
123                                 _ownerThread = Thread.CurrentThread;
124                                 _lockCount++;
125                         }
126                 }
127                 
128                 internal void ReleaseLock ()
129                 {
130                         lock (this)
131                         {
132                                 if (_lockCount > 0 && _ownerThread == Thread.CurrentThread) {
133                                         _lockCount--;
134                                         _mutex.ReleaseMutex ();
135                                         if (_lockCount == 0) {
136                                                 _ownerThread = null;
137                                         }
138                                 }
139                         }
140                 }
141                 
142                 [System.Runtime.InteropServices.ComVisible (true)]
143                 public override void GetPropertiesForNewContext (IConstructionCallMessage ctorMsg)
144                 {
145                         if (_flavor != NOT_SUPPORTED) {
146                                 ctorMsg.ContextProperties.Add (this);
147                         }
148                 }
149                 
150                 public virtual IMessageSink GetClientContextSink (IMessageSink nextSink)
151                 {
152                         return new SynchronizedClientContextSink (nextSink, this);
153                 }
154                 
155                 public virtual IMessageSink GetServerContextSink (IMessageSink nextSink)
156                 {
157                         return new SynchronizedServerContextSink (nextSink, this);
158                 }
159                 
160                 [System.Runtime.InteropServices.ComVisible (true)]
161                 public override bool IsContextOK (Context ctx, IConstructionCallMessage msg)
162                 {
163                         SynchronizationAttribute prop = ctx.GetProperty ("Synchronization") as SynchronizationAttribute;
164                         switch (_flavor)
165                         {
166                                 case NOT_SUPPORTED: return (prop == null);
167                                 case REQUIRED: return (prop != null);
168                                 case REQUIRES_NEW: return false;
169                                 case SUPPORTED: return true;
170                         }
171                         return false;
172                 }
173                 
174                 internal static void ExitContext ()
175                 {
176                         if (Thread.CurrentContext.IsDefaultContext) return;
177                         SynchronizationAttribute prop = Thread.CurrentContext.GetProperty ("Synchronization") as SynchronizationAttribute;
178                         if (prop == null) return;
179                         prop.Locked = false;
180                 }
181                 
182                 internal static void EnterContext ()
183                 {
184                         if (Thread.CurrentContext.IsDefaultContext) return;
185                         SynchronizationAttribute prop = Thread.CurrentContext.GetProperty ("Synchronization") as SynchronizationAttribute;
186                         if (prop == null) return;
187                         prop.Locked = true;
188                 }
189         }
190         
191         internal class SynchronizedClientContextSink: IMessageSink
192         {
193                 IMessageSink _next;
194                 SynchronizationAttribute _att;
195                 
196                 public SynchronizedClientContextSink (IMessageSink next, SynchronizationAttribute att)
197                 {
198                         _att = att;
199                         _next = next;
200                 }
201                 
202                 public IMessageSink NextSink 
203                 {
204                         get { return _next; }
205                 }
206                 
207                 public IMessageCtrl AsyncProcessMessage (IMessage msg, IMessageSink replySink)
208                 {
209                         if (_att.IsReEntrant)
210                         {
211                                 _att.ReleaseLock();     // Unlock when leaving the context
212                                 replySink = new SynchronizedContextReplySink (replySink, _att, true);
213                         }
214                         return _next.AsyncProcessMessage (msg, replySink);
215                 }
216
217                 public IMessage SyncProcessMessage (IMessage msg)
218                 {
219                         if (_att.IsReEntrant) 
220                                 _att.ReleaseLock ();    // Unlock when leaving the context
221                         
222                         try
223                         {
224                                 return _next.SyncProcessMessage (msg);
225                         }
226                         finally
227                         {
228                                 if (_att.IsReEntrant)
229                                         _att.AcquireLock ();
230                         }
231                 }
232         }
233         
234         internal class SynchronizedServerContextSink: IMessageSink
235         {
236                 IMessageSink _next;
237                 SynchronizationAttribute _att;
238                 
239                 public SynchronizedServerContextSink (IMessageSink next, SynchronizationAttribute att)
240                 {
241                         _att = att;
242                         _next = next;
243                 }
244                 
245                 public IMessageSink NextSink 
246                 {
247                         get { return _next; }
248                 }
249                 
250                 public IMessageCtrl AsyncProcessMessage (IMessage msg, IMessageSink replySink)
251                 {
252                         _att.AcquireLock ();
253                         replySink = new SynchronizedContextReplySink (replySink, _att, false);
254                         return _next.AsyncProcessMessage (msg, replySink);
255                 }
256
257                 public IMessage SyncProcessMessage (IMessage msg)
258                 {
259                         _att.AcquireLock ();
260                         try
261                         {
262                                 return _next.SyncProcessMessage (msg);
263                         }
264                         finally
265                         {
266                                 _att.ReleaseLock ();
267                         }
268                 }
269         }
270         
271         internal class SynchronizedContextReplySink: IMessageSink
272         {
273                 IMessageSink _next;
274                 bool _newLock;
275                 SynchronizationAttribute _att;
276         
277                 public SynchronizedContextReplySink (IMessageSink next, SynchronizationAttribute att, bool newLock)
278                 {
279                         _newLock = newLock;
280                         _next = next;
281                         _att = att;
282                 }
283                 
284                 public IMessageSink NextSink 
285                 {
286                         get { return _next; }
287                 }
288                 
289                 public IMessageCtrl AsyncProcessMessage (IMessage msg, IMessageSink replySink)
290                 {
291                         // Never called
292                         throw new NotSupportedException ();
293                 }
294
295                 public IMessage SyncProcessMessage (IMessage msg)
296                 {
297                         if (_newLock) _att.AcquireLock ();
298                         else _att.ReleaseLock ();
299
300                         try
301                         {
302                                 return _next.SyncProcessMessage (msg);
303                         }
304                         finally
305                         {
306                                 if (_newLock)
307                                         _att.ReleaseLock ();
308                         }
309                 }
310         }
311 }
312