System.Drawing: added email to icon and test file headers
[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                 bool _locked;
51                 [NonSerialized]
52                 int _lockCount = 0;
53                 
54                 [NonSerialized]
55                 Mutex _mutex = new Mutex (false);
56                 [NonSerialized]
57                 Thread _ownerThread;
58                 
59                 public SynchronizationAttribute ()
60                 : this (REQUIRES_NEW, false)
61                 {
62                 }
63                 
64                 public SynchronizationAttribute (bool reEntrant)
65                 : this (REQUIRES_NEW, reEntrant)
66                 {
67                 }
68                 
69                 public SynchronizationAttribute (int flag)
70                 : this (flag, false)
71                 {
72                 }
73                 
74                 public SynchronizationAttribute (int flag, bool reEntrant)
75                 : base ("Synchronization")
76                 {
77                         if (flag != NOT_SUPPORTED && flag != REQUIRED && flag != REQUIRES_NEW && flag != SUPPORTED)
78                                 throw new ArgumentException ("flag");
79                                 
80                         _bReEntrant = reEntrant;
81                         _flavor = flag;
82                 }
83                 
84                 public virtual bool IsReEntrant
85                 {
86                         get { return _bReEntrant; }
87                 }
88                 
89                 public virtual bool Locked
90                 {
91                         get 
92                         { 
93                                 return _locked; 
94                         }
95                         
96                         set 
97                         {
98                                 if (value)
99                                 {
100                                         _mutex.WaitOne ();
101                                         lock (this)
102                                         {
103                                                 _lockCount++;
104                                                 if (_lockCount > 1)
105                                                         ReleaseLock (); // Thread already had the lock
106                                                         
107                                                 _ownerThread = Thread.CurrentThread;
108                                         }
109                                 }
110                                 else
111                                 {
112                                         lock (this)
113                                         {
114                                                 while (_lockCount > 0 && _ownerThread == Thread.CurrentThread)
115                                                 {
116                                                         _lockCount--;
117                                                         _mutex.ReleaseMutex ();
118                                                         _ownerThread = null;
119                                                 }
120                                         }
121                                 }
122                         }
123                 }
124                 
125                 internal void AcquireLock ()
126                 {
127                         _mutex.WaitOne ();
128                         
129                         lock (this)
130                         {
131                                 _ownerThread = Thread.CurrentThread;
132                                 _lockCount++;
133                         }
134                 }
135                 
136                 internal void ReleaseLock ()
137                 {
138                         lock (this)
139                         {
140                                 if (_lockCount > 0 && _ownerThread == Thread.CurrentThread) {
141                                         _lockCount--;
142                                         _mutex.ReleaseMutex ();
143                                         _ownerThread = null;
144                                 }
145                         }
146                 }
147                 
148                 [System.Runtime.InteropServices.ComVisible (true)]
149                 public override void GetPropertiesForNewContext (IConstructionCallMessage ctorMsg)
150                 {
151                         if (_flavor != NOT_SUPPORTED) {
152                                 ctorMsg.ContextProperties.Add (this);
153                         }
154                 }
155                 
156                 public virtual IMessageSink GetClientContextSink (IMessageSink nextSink)
157                 {
158                         return new SynchronizedClientContextSink (nextSink, this);
159                 }
160                 
161                 public virtual IMessageSink GetServerContextSink (IMessageSink nextSink)
162                 {
163                         return new SynchronizedServerContextSink (nextSink, this);
164                 }
165                 
166                 [System.Runtime.InteropServices.ComVisible (true)]
167                 public override bool IsContextOK (Context ctx, IConstructionCallMessage msg)
168                 {
169                         SynchronizationAttribute prop = ctx.GetProperty ("Synchronization") as SynchronizationAttribute;
170                         switch (_flavor)
171                         {
172                                 case NOT_SUPPORTED: return (prop == null);
173                                 case REQUIRED: return (prop != null);
174                                 case REQUIRES_NEW: return false;
175                                 case SUPPORTED: return true;
176                         }
177                         return false;
178                 }
179                 
180                 internal static void ExitContext ()
181                 {
182                         if (Thread.CurrentContext.IsDefaultContext) return;
183                         SynchronizationAttribute prop = Thread.CurrentContext.GetProperty ("Synchronization") as SynchronizationAttribute;
184                         if (prop == null) return;
185                         prop.Locked = false;
186                 }
187                 
188                 internal static void EnterContext ()
189                 {
190                         if (Thread.CurrentContext.IsDefaultContext) return;
191                         SynchronizationAttribute prop = Thread.CurrentContext.GetProperty ("Synchronization") as SynchronizationAttribute;
192                         if (prop == null) return;
193                         prop.Locked = true;
194                 }
195         }
196         
197         internal class SynchronizedClientContextSink: IMessageSink
198         {
199                 IMessageSink _next;
200                 SynchronizationAttribute _att;
201                 
202                 public SynchronizedClientContextSink (IMessageSink next, SynchronizationAttribute att)
203                 {
204                         _att = att;
205                         _next = next;
206                 }
207                 
208                 public IMessageSink NextSink 
209                 {
210                         get { return _next; }
211                 }
212                 
213                 public IMessageCtrl AsyncProcessMessage (IMessage msg, IMessageSink replySink)
214                 {
215                         if (_att.IsReEntrant)
216                         {
217                                 _att.ReleaseLock();     // Unlock when leaving the context
218                                 replySink = new SynchronizedContextReplySink (replySink, _att, true);
219                         }
220                         return _next.AsyncProcessMessage (msg, replySink);
221                 }
222
223                 public IMessage SyncProcessMessage (IMessage msg)
224                 {
225                         if (_att.IsReEntrant) 
226                                 _att.ReleaseLock ();    // Unlock when leaving the context
227                         
228                         try
229                         {
230                                 return _next.SyncProcessMessage (msg);
231                         }
232                         finally
233                         {
234                                 if (_att.IsReEntrant)
235                                         _att.AcquireLock ();
236                         }
237                 }
238         }
239         
240         internal class SynchronizedServerContextSink: IMessageSink
241         {
242                 IMessageSink _next;
243                 SynchronizationAttribute _att;
244                 
245                 public SynchronizedServerContextSink (IMessageSink next, SynchronizationAttribute att)
246                 {
247                         _att = att;
248                         _next = next;
249                 }
250                 
251                 public IMessageSink NextSink 
252                 {
253                         get { return _next; }
254                 }
255                 
256                 public IMessageCtrl AsyncProcessMessage (IMessage msg, IMessageSink replySink)
257                 {
258                         _att.AcquireLock ();
259                         replySink = new SynchronizedContextReplySink (replySink, _att, false);
260                         return _next.AsyncProcessMessage (msg, replySink);
261                 }
262
263                 public IMessage SyncProcessMessage (IMessage msg)
264                 {
265                         _att.AcquireLock ();
266                         try
267                         {
268                                 return _next.SyncProcessMessage (msg);
269                         }
270                         finally
271                         {
272                                 _att.ReleaseLock ();
273                         }
274                 }
275         }
276         
277         internal class SynchronizedContextReplySink: IMessageSink
278         {
279                 IMessageSink _next;
280                 bool _newLock;
281                 SynchronizationAttribute _att;
282         
283                 public SynchronizedContextReplySink (IMessageSink next, SynchronizationAttribute att, bool newLock)
284                 {
285                         _newLock = newLock;
286                         _next = next;
287                         _att = att;
288                 }
289                 
290                 public IMessageSink NextSink 
291                 {
292                         get { return _next; }
293                 }
294                 
295                 public IMessageCtrl AsyncProcessMessage (IMessage msg, IMessageSink replySink)
296                 {
297                         // Never called
298                         throw new NotSupportedException ();
299                 }
300
301                 public IMessage SyncProcessMessage (IMessage msg)
302                 {
303                         if (_newLock) _att.AcquireLock ();
304                         else _att.ReleaseLock ();
305
306                         try
307                         {
308                                 return _next.SyncProcessMessage (msg);
309                         }
310                         finally
311                         {
312                                 if (_newLock)
313                                         _att.ReleaseLock ();
314                         }
315                 }
316         }
317 }
318